如何让页面尽可能早地渲染页面,页面更早可见,让白屏时间更短,尤其是无线环境下,一直是性能优化的话题。
页面可见时间
页面可见要经历以下过程:
- 解析 HTML 为 DOM,解析 CSS 为 CSSOM(CSS Object Model)
- 将 DOM 和 CSSOM 合成一棵渲染树( render tree )
- 完成渲染树的布局(layout)
- 将渲染树绘制到屏幕
layout
由于 JS 可能随时会改变 DOM 和 CSSOM ,当页面中有大量的 JS 想立刻执行时,浏览器下载并执行,直到完成 CSSOM 下载与构建,而在我们等待时,DOM 构建同样被阻塞。为了 JS 不阻塞 DOM 和 CSSDOM 的构建,不影响首屏可见的时间,测试几种 JS 加载策略对页面可见的影响:
几种异步加载方式测试
- A. head script: 即普通的将 JS 放在 head 中或放在 body 中间: DEMO 地址
- B. bottom script: 即常规的优化策略,JS 放 body 的底部: DEMO 地址
-
C. document.write: 以前 PC 优化少用的一种异步加载 JS 的策略: DEMO 地址
function injectWrite(src){ document.write('<script src="' + src + '"></sc' + 'ript>');}
-
D. getScript: 形如以下,也是 KISSY 内部的 getScript 函数的简易实现: DEMO 地址
<script> var script = document.createElement('script'); script.src = "//g.tbcdn.com/xx.js"; document.getElementsByTagName('head')[0].appendChild(script);</script>
-
E. 加 async 属性: DEMO 地址
- F. 加 defer 属性: DEMO 地址
- G. 同时加 async defer 属性: DEMO 地址
测试结果
以下提到的 domReady 同 DOMContentLoaded 事件。
A (head script) | B (bottom script) | C (document.write) | D (getScript) | E (async) | F (defer) | G (async + defer) | ||
---|---|---|---|---|---|---|---|---|
1 | PC Chrome | 页面白屏长、domReady:5902.545、onLoad:5931.48 | 页面先显示、domReady:5805.21、onLoad:5838.255 | 页面先显示、domReady:5917.95、onLoad:5949.30 | 页面先显示、domReady:244.41、onLoad:5857.645 | 页面先显示、domReady:567.01、onLoad:5709.33 | 页面先显示、domReady:5812.12、onLoad:5845.6 | 页面先显示、domReady:576.12、onLoad:5743.79 |
2 | iOS Safari | 页面白屏长、domReady:6130、onLoad:6268.41 | 页面白屏长、domReady:5175.80、onLoad:5182.75 | 页面白屏长、domReady:5617.645、onLoad:5622.115 | 502s 白屏然后页面显示最后变更 load finish 时间、domReady:502.71、onLoad:6032.95 | 508s 白屏然后页面显示最后变更 load finish time domReady:508.95、onLoad:5538.135 | 页面白屏长、domReady:5178.98、onLoad:5193.58 | 556s 白屏然后页面显示最后变更 load finish 时间、domReady:556、onLoad:5171.95 |
3 | iOS 手淘 WebView | 页面白屏长、页面出现 loading 消失、domReady: 5291.29、onLoad:5292.78 | 页面白屏长、页面未跳转 loading 消失、domReady: 5123.46、onLoad:5127.85 | 页面白屏长、页面未跳转 loading 消失、domReady: 5074.86、onLoad:5079.875 | 页面可见快、loading 消失快在 domReady 稍后、domReady:14.06、load finish:5141.735 | 页面可见快、loading 消失快在 domReady 稍后、domReady:13.89、load finish:5157.15 | 页面白屏长、loading 先消失再出现页面、domReady: 5132.395、onLoad:5137.52 | 页面可见快、然后 loading 消失、domReady:13.49、load finish:5124.08 |
4 | Android browser | 页面白屏长、domReady: 5097.29、onLoad:5100.37 | 页面白屏长、domReady: 5177.48、onLoad:5193.66 | 页面白屏长、domReady: 5125.96、onLoad:5165.06 | 页面可见快、等 5s 后更新 load finish 时间 domReady:463.33、load finish:5092.90 | 页面可见快、等 5s 后更新 load finish 时间 domReady:39.34、load finish:5136.55 | 页面白屏长、domReady: 5092.45、onLoad:5119.81 | 页面可见快、等 5s 后更新 load finish 时间 domReady:50.49、load finish:5507.668 |
5 | Android 手淘 WebView | 白屏时间长、一直 loading 直接页面可见、domReady:5058.91、onLoad:5073.81 | 页面立即可见、loading 消失快、等 5s 后更新 domReady 时间和 load 时间 domReady:4176.34、onLoad:4209.50 | 页面立即可见、loading 消失快、domReady:6011.18、onLoad:6031.93 | 页面可见快、loading 之后消失、等 5s 后更新 load finish 时间 domReady:36.31、load finish:5081.76 | 页面可见快、loading 随后消失、等 5s 后更新 load finish 时间 domReady:25.11、load finish:5113.81 | 页面可见快、loading 随后消失、等 5s 后更新 domReady 时间和 load 时间 domReady:5213.11、load finish:5312.19 | 页面可见快、loading 随后消失、等 5s 后更新 load finish 时间 domReady:89.67、load finish:5589.95 |
从以上测试结果可以看出以下结论:
- 横向看, iOS Safari 和 Android browser 的在页面可见、domReady、onLoad 的时间表现一致。
- 纵向看,bottom script、document.write 和 defer 三列,可知 document.write 和 defer 无任何异步效果,可见时间、domReady、onLoad 的触发时间和 bottom script 的情况一致。
- 纵向看,async + defer 联合用和 async 的表现一致,故合并为 async。
- 纵向看,script 放页头(head script)和 script 放 body 底部(bottom script)。iOS Safari 、Android browser 和 iOS WebView 表现一致,即使 script 放在 body 的底部也无济于事,页面白屏时间长,要等到 domReady 5s 多后结束才显示页面;唯独 Android WebView 的表现和 PC 的 Chrome 一致。
- 单纯看手淘 WebView 容器中 loading 消失的时间,这个时间点 iOS 和 Android 的表现一致,即都是在 UIWebView 的 didFinishLoad 事件触发时消失。这个事件的触发可能在 domReady 之前(如:A3、B3),也可能在 domReady 之后(如:D3、E3);这个事件触发和 JS 中的 onLoad 触发时机也没有必然的联系,可能在 onLoad 之前(如:D3、E3)也可能在 onLoad 几乎同时(如:A5)。 didiFinishLoad 到底是什么时机触发的呢,详见下章。
- 页面可见时间,getScript 方式和 async 方式页面可见都非常快,domReady 的时间触发得也非常快,客户端的 loading 在 domReady 稍后即消失。原因是因为 最后耗时的 JS 请求异步化了 ,没有阻塞浏览器的 DOM + CSSOM 构建,页面渲染完成就立刻可见了。整体看,如果 domReady 的时间快,则页面可见快;反之如果页面可见快,domReady 的时间不一定快,如 B5、B1、C1、C5、F1、F5。如果异步化耗时长的 JS,domReady 和 onLoad 的时间差距是很大的,不做任何处理 onLoad 的时间 domReady 的时间差 30ms 左右。所以在异步化的前提下,可以用 domReady 的时间作为页面可见的时间。
didFinishLoad 到底什么时候触发
didFinishLoad 是 native 定义的事件,该事件触发时手淘 loading 菊花消失,并且 windvane 中的发出请求不再收集,也就是 native 统计出的 pageLoad 时间。在用户数据平台看到的瀑布流请求,就是在 didFinishLoad 触发前收集到的所有请求。
经过上方测试,客户端的 didFinisheLoad 事件的触发和 JS 中的 domReady(DOMContentLoaded)和 onLoad 触发没有任何关联。可能在 domReady 之前或之后,也可能在 onLoad 之前或之后。
那它到底是什么时候触发呢? iOS 官方文档 是 Sent after a web view finishes loading a frame。 结合收集的用户请求和测试,didFinishLoad 是在连续发起的请求结束之后触发,监听一段时间内无请求则触发。
所以经常会看到 data_sufei 这个 JS 文件,在有些用户的瀑布流里面有,在有些用户的又没有。原因是这个 JS 是 aplus_wap.js 故意 setTimeout 1s 后发出的,如果页面在 1s 前所有的请求都发完了则触发 didFinishLoad,后面的 data_sufei.js 的时间就不算到 pageLoad 的时间;反之如果接近 1s 页面还有图片等请求还在发,则 data_sufei.js 的时间也会被算到里面。
因此在 JS 中用 setTimeout 来延迟发送请求也有可能会影响 didFinishLoad 的时间,建议 setTimeout 的时间设置得更长一点,如 3s。
async 和 defer
script 标签上可以添加 defer 和 async 属性来优化此 script 的下载和执行。
defer :延迟
HTML 4.0 规范,其作用是,告诉浏览器,等到 DOM+CSSOM 渲染完成,再执行指定脚本。
<script defer src="xx.js"></script> |
- 浏览器开始解析 HTML 网页
- 解析过程中,发现带有 defer 属性的 script 标签
- 浏览器继续往下解析 HTML 网页,解析完就渲染到页面上,同时并行下载 script 标签中的外部脚本
- 浏览器完成解析 HTML 网页,此时再执行下载的脚本,完成后触发 DOMContentLoaded
下载的脚本文件在 DOMContentLoaded 事件触发前执行(即刚刚读取完\标签),而且可以保证执行顺序就是它们在页面上出现的顺序。所以 添加 defer 属性后,domReady 的时间并没有提前,但它可以让页面更快显示出来。
将放在页面上方的 script 加 defer,在 PC Chrome 下其效果相当于 把这个 script 放在底部,页面会先显示。 但对 iOS Safari 和 iOS WebView 加 defer 和 script 放底部一样都是长时间白屏。
async: 异步
HTML 5 规范,其作用是,使用另一个进程下载脚本,下载时不会阻塞渲染,并且下载完成后立刻执行。
<script async src="yy.js"></script> |
- 浏览器开始解析 HTML 网页
- 解析过程中,发现带有 async 属性的 script 标签
- 浏览器继续往下解析 HTML 网页,解析完先显示页面并触发 DOMContentLoaded,同时并行下载 script 标签中的外部脚本
- 脚本下载完成,浏览器暂停解析 HTML 网页,开始执行下载的脚本
- 脚本执行完毕,浏览器恢复解析 HTML 网页
async 属性可以保证脚本下载的同时,浏览器继续渲染。但是 async 无法保证脚本的执行顺序。哪个脚本先下载结束,就先执行那个脚本。
如何选择 async 和 defer
- defer 可以保证执行顺序, async 不行【注:
- async 可以提前触发 domReady , defer 不行【注:Firefox 的 defer 也可以提前触发 domready 】
- defer 在 iOS 和部分 Android 下依然阻塞渲染,白屏时间长。
- 当 script 同时加 async 和 defer 属性时,后者不起作用,浏览器行为由 async 属性决定。
- async 和 defer 的兼容性不一致,好在 async 和 defer 无线端基本都支持, async 不支持 IE 9-。 附 async 兼容性 defer 兼容性
script inject 和 async
<!-- BAD --><script src="//g.alicdn.com/large.js"></script><!-- GOOD --><script> var script = document.createElement('script'); script.src = "//g.alicdn.com/large.js"; document.getElementsByTagName('head')[0].appendChild(script);</script> |
我们通常用这种 inject script 的方式来异步加载文件,特别是以前 Sea.js 、 KISSY 的盛行时,出现大量使用 $.use 来加载页面入口文件。这种方式和 async 的一样都能异步化 JS,不阻塞页面渲染。但真的是最快的吗?
一个常见的页面如下:一个 CSS,两个异步的 JS
JS 使用 script inject 的方式测试结果如下, DEMO :
JS 使用 async 的方式测试结果如下, DEMO :
对比结果发现,通过
也许大家会说,现在 CSS/JS 都预加载到客户端了,怎么加载不重要。但页面有可能分享出去也有可能运行在浏览器中,也有可能预加载失效。
综合上面 async 和 defer,推荐以下用法。
<!-- 现代浏览器用 'async', ie9-用 'defer' --><script src="//g.alicdn.com/alilog/mlog/aplus_wap.js" async defer></script> |
其实现在无线站点 aplus.js 可以完全用这种方式引入,既不会阻塞 DOM 和 CSSOM ,也不会延长整个页面 onLoad 时间,而不是原来的 PC 上的 script inject 方式。
如果 aplus.js 在 PC 上这么用,IE 8/IE 9 应用的是 defer 属性,不会阻塞页面渲染,但是这个 JS 需要执行完后才触发 domReady(DOMContentLoaded)事件,故在 IE 8/IE 9 下可能会影响 domReady 的时间。
最后建议
- 业务 JS 尽量异步,放 body 底部的 JS 在 iOS 上和部分 Android 是无效的,依然会阻塞首屏渲染。
- 异步的方式尽可能原生用 async ,容器(浏览器、webview 等)级别自带优化,不要通过 JS 去模拟实现,如 getScript/ajax/KISSY.use/$.use 等。
- 有顺序依赖关系的 JS 可以加 defer,不改变执行顺序,相当于放到页面底部,如 TMS head 中一时无法挪动位置的类库等。

HTML의 역할은 태그 및 속성을 통해 웹 페이지의 구조와 내용을 정의하는 것입니다. 1. HTML은 읽기 쉽고 이해하기 쉽게하는 태그를 통해 컨텐츠를 구성합니다. 2. 접근성 및 SEO와 같은 시맨틱 태그 등을 사용하십시오. 3. HTML 코드를 최적화하면 웹 페이지로드 속도 및 사용자 경험이 향상 될 수 있습니다.

"Code"는 "Code"BroadlyIncludeLugageslikeJavaScriptandPyThonforFunctureS (htMlisAspecificTypeofCodeFocudecturecturingWebContent)

HTML, CSS 및 JavaScript는 웹 개발의 세 가지 기둥입니다. 1. HTML은 웹 페이지 구조를 정의하고 등과 같은 태그를 사용합니다. 2. CSS는 색상, 글꼴 크기 등과 같은 선택기 및 속성을 사용하여 웹 페이지 스타일을 제어합니다.

HTML은 웹 구조를 정의하고 CSS는 스타일과 레이아웃을 담당하며 JavaScript는 동적 상호 작용을 제공합니다. 세 사람은 웹 개발에서 의무를 수행하고 화려한 웹 사이트를 공동으로 구축합니다.

HTML은 간단하고 배우기 쉽고 결과를 빠르게 볼 수 있기 때문에 초보자에게 적합합니다. 1) HTML의 학습 곡선은 매끄럽고 시작하기 쉽습니다. 2) 기본 태그를 마스터하여 웹 페이지를 만들기 시작하십시오. 3) 유연성이 높고 CSS 및 JavaScript와 함께 사용할 수 있습니다. 4) 풍부한 학습 리소스와 현대 도구는 학습 과정을 지원합니다.

anexampleStartingtaginhtmlis, whithbeginsaparagraph.startingtagsareessentialinhtmlastheyinitiate rements, definetheirtypes, andarecrucialforstructurituringwebpages 및 smanstlingthedom.

메뉴에서 점선 분할 효과를 설계하는 방법은 무엇입니까? 메뉴를 설계 할 때는 일반적으로 접시 이름과 가격 사이에 왼쪽과 오른쪽을 정렬하는 것이 어렵지 않지만 점선 또는 중간의 점은 어떻습니까?

웹 코드 편집기의 HTML 요소 분석 많은 온라인 코드 편집기를 사용하면 사용자가 HTML, CSS 및 JavaScript 코드를 입력 할 수 있습니다. 최근에 누군가가 제안했습니다 ...


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

맨티스BT
Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

ZendStudio 13.5.1 맥
강력한 PHP 통합 개발 환경

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

Atom Editor Mac 버전 다운로드
가장 인기 있는 오픈 소스 편집기

뜨거운 주제



