网上关于文件加载与页面阻塞的文章多如牛毛,大致可分类两类:
- 纯抄(或参考)《高性能javascript》和《高性能网站建设指南》
- 有测试并有截图和解释,但存在如下问题:
- 不全面,如可能只提到Chrome是如何加载的(毕竟它的Timeline太好用了)
- 读者很难重现作者的步骤,一方面是给了一个死链(虽然当时是好的),另一种情况是没有源代码和文件
在《高性能网站建设指南》中,Steve Souders给出了许多有用的链接,让用户通过实际的测试来感受页面的阻塞。美中不足的是:
- 源代码是Perl,实在不想阅读
- 虽然url是可配置的,但使用起来还是有点麻烦的
研究这类问题完全没有多少规律可循,兴许IE6只这么一回事,IE8确又是另一种奇葩结果。如果只是读一读别人的文章,如上面两本书和许多其它的博文,很难全面的建立起比较全面的了解。
基于这种情况,我用node写了一个非常简单的服务器程序Blocking,方便自己做测试。
约定
对于<script src='/t/wait-3s.js' ></script>
,表示:
- 这个js文件会延迟3秒下载,当浏览器执行它时,会打印
execute /t/wait-3s.js
的字样
对于<script src='/t/wait-2s-busy-4s.js' ></script>
- 这个js文件会延迟2秒下载,且脚本会执行4秒。会打印
start execute /t/wait-2s-busy-4s.js
和end execute ...
字样
对于<link href="/t/wait-6s-red.css" type="text/css" rel="stylesheet">
,表示
- 这个css文件会延迟6秒下载,且内容为body{background:red}
其它:
- 所有[request]标识的log信息都是Server在接收到请求时打印出来的
- 其它的log信息都是客户端调用
g.log
打印出来的
示例
其实主要是为了瞅一瞅上古版本的IE行为了,对于Chrome这种现代浏览器,若有心的话,看它的Timeline可比这个工具的log信息更精确
步骤:
首先,你要有git
和node
。
git clone https://github.com/ssnau/blocking.git
npm install
node main.js
- 打开
http://localhost:5000
下面以IE6和Chrome为例。
IE6
对于如下代码:
注:下面的代码省略掉了打印log的必要部分,g.log函数实际上是发了一个xhr到server端请求log消息
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Defer Test</title>
<script src='/t/wait-4s-defer.js' defer></script>
<script src='/t/wait-4s-defer2.js' defer></script>
<script src='/t/wait-2s-1.js' ></script>
<script src='/t/wait-2s-2.js' ></script>
<script src='/t/wait-2s-3.js' ></script>
<link href="/t/wait-6s-red.css" type="text/css" rel="stylesheet">
<script src='/t/wait-2s-another.js' ></script>
<link href="/t/wait-4s-lightblue.css" type="text/css" rel="stylesheet">
</head>
<body>
<h1>Hello World</h1>
<img src="/t/wait-10s.jpg" />
</body>
</html>
在IE6中,我们可以看到如下的log信息:
[219ms]HTML downloaded #在219ms时页面加载完成
[340ms][request] /t/wait-4s-defer.js #有defer属性的script是可以并行下载的
[341ms][request] /t/wait-4s-defer2.js
[4343ms][request] /t/wait-2s-1.js #4秒之后,开始下载wait-2s-1.js
[6266ms]execute /t/wait-2s-1.js
[6363ms][request] /t/wait-2s-2.js
[8281ms]execute /t/wait-2s-2.js
[8383ms][request] /t/wait-2s-3.js
[10297ms]execute /t/wait-2s-3.js #上面的script都有阻塞效果,即仅上前一个下载完毕且执行完,后一下才开始下载
[10400ms][request] /t/wait-6s-red.css
[10402ms][request] /t/wait-2s-another.js #css和js可并行下载
[16328ms]execute /t/wait-2s-another.js #尽管js只延时2s,但却要等到延迟6s的css下载完毕才开始执行,奇葩吧?
[16432ms][request] /t/wait-4s-lightblue.css
[16436ms][request] /t/wait-10s.jpg #css和jpg并行下载
[20391ms]execute /t/wait-4s-defer.js
[20391ms]execute /t/wait-4s-defer2.js #在dom ready前执行defer
[26359ms]DOM fully loaded and parsed
[26359ms]window loaded #image加载完后才window loaded
对IE6可以有如下结论:
- IE6对同一个域名,最多只会同时并发两个请求。(积极响应HTTP规范建议啊。。
- 在没有Defer的情况下,一次只能下载一个Javascript文件,且JS文件的下载会阻塞其它文件的下载。
- css文件的下载不会阻塞JS文件的下载,如前一个是css文件,后一个是JS文件,那么它们会并行下载。
- 这里有一个问题是,后一个JS文件会延迟执行,直到前面的css文件下载完毕。(谁能告诉我为什么会这样。。
- 另一个问题,如果css文件和JS文件来自不同域,结果会怎样?
- 如果有设置了defer,那JS文件是并行下载的,不会产生阻塞。
- defer的script会在DomReady之前解释执行
Chrome 34
得到如下log信息:(Chrome有Network
和Timeline
,界面比这个log友好)-_-||
[531ms]HTML downloaded #在531ms时页面加载完成
[538ms][request] /t/wait-6s-red.css
[558ms][request] /t/wait-4s-lightblue.css
[840ms][request] /t/wait-4s-defer.js
[840ms][request] /t/wait-4s-defer2.js
[841ms][request] /t/wait-2s-1.js
[841ms][request] /t/wait-2s-2.js #6个并发
[2836ms][request] /t/wait-2s-3.js #直到2s延迟的下载完毕后,才开始发送新的请求
[2837ms][request] /t/wait-2s-another.js
[2835ms]execute /t/wait-2s-1.js
[2835ms]execute /t/wait-2s-2.js
[4556ms][request] /t/wait-10s.jpg
[4837ms]execute /t/wait-2s-3.js
[6537ms]execute /t/wait-2s-another.js
[6537ms]execute /t/wait-4s-defer.js
[6538ms]execute /t/wait-4s-defer2.js
[6538ms]DOM fully loaded and parsed
[14559ms]window loaded
对Chrome34的结论:
- 对同一个域名,最多会有6个并发下载
- Javascript文件的下载不会阻塞其它文件下载
- defer属性的JS文件,会等在DomReady前一刻执行
Next
上面的只是例子而已,毕竟测试组合实在太多,只有在需要测试的时候我才会去搭理。比如:
- script放在body中,加载时会阻塞后面文件的加载吗?
- 一个CSS在head中,另一个在body底部,中间有一个长延时的js文件,页面会因为两次计算CSS而闪烁吗?如果js文件没有延时,但执行时间较长会怎么样?IE6是什么情况?那IE10呢?那Chrome又如何?
- CSS有@import超长延时的文件会怎样?
这个工具仍然只是雏形中的雏形,如果觉得还凑合的话,欢迎提出建议和PR。
还是强烈建议看一下Steve Souders的书,如果你对实验没什么兴趣的话,严格遵守他的建议就足够了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。