Dynamic JS Loader

48
以下人群请勿阅读此系列 PPT 输入地址, 3 秒之后窗口仍然空白一片,但没有 感觉任何不适 不相信优化网站性能会带来更多的效益 不认为页面速度提升能够带来客户满意度提升 压根就不认为优化网站性能可以改变命运

Transcript of Dynamic JS Loader

Page 1: Dynamic JS Loader

以下人群请勿阅读此系列 PPT

• 输入地址, 3秒之后窗口仍然空白一片,但没有感觉任何不适

• 不相信优化网站性能会带来更多的效益• 不认为页面速度提升能够带来客户满意度提升• 压根就不认为优化网站性能可以改变命运

Page 2: Dynamic JS Loader

Section II

Dynamic JS Loader

Ctrip 前端开发 feifeipan Email : [email protected]

Section I 请参看 高性能网站建设

Page 3: Dynamic JS Loader

… …思考

我们真的认为性能很重要吗?

Page 4: Dynamic JS Loader

… …发现

• 亚马逊发现,网站每慢 0.1秒等于丢失 600万美元的销售额。

• Google则发现,网页载入慢 0.5秒会导致20%的用户流失。

• Ctrip发现了吗?

Page 5: Dynamic JS Loader

… …思考

我们怎么引用 JS文件?

Page 6: Dynamic JS Loader

曾经(或现在)

Page 7: Dynamic JS Loader

…总是认为

随便找个地儿放一下JS,只要页面不报错就行啦

Page 8: Dynamic JS Loader

… …结果总是

• 曾经的痛

Page 9: Dynamic JS Loader

… …结果总是

为啥总是空白呢?空白还是空白 !!

Page 10: Dynamic JS Loader

… …因为

• 浏览器在解析到 <body>之前,不会渲染页面任何部分。

• 无论是内嵌还是外链,页面的下载和渲染都必须停下来等待脚本执行完成。

Page 11: Dynamic JS Loader

解决方案

• 将脚本放在底部• 减少脚本文件的大小• 限制 HTTP请求数

Page 12: Dynamic JS Loader

… …思考

JS真的需要在页面渲染的时候一起加载吗?

JS可以在需要的时候才加载吗?

JS可以先缓存好,等需要的时候再执行吗?

Page 13: Dynamic JS Loader

无阻塞脚本

在页面加载完成之后才加载 Javascript代码

Page 14: Dynamic JS Loader

无阻塞的脚本之延迟脚本

• 延迟的脚本

<script src=‘file.js’ defer></script>

defer 表明该脚本不会修改 DOM, 因此能安全地延迟执行。

Page 15: Dynamic JS Loader

无阻塞的脚本之延迟脚本

延迟的脚本 { 测试结果 }

注 : firefox3.6不支持 defer属性

只有 I E6.0+ 和 Firefox3.5 支持,其余浏览器均不支持

Page 16: Dynamic JS Loader

动态脚本元素

无阻塞的脚本之动态脚本元素

在页面中创建脚本节点,并添加到 D OM 中

Page 17: Dynamic JS Loader

动态脚本元素

无阻塞的脚本之动态脚本元素

可以实时监听到加载结束,添加回调函数

Page 18: Dynamic JS Loader

动态脚本元素 { 测试结果 }

无阻塞的脚本之动态脚本元素

• 无论何时启动下载,文件的下载和执行过程不会阻塞页面其他进程。

注:加在 head中比在 body中要可靠,防止 I E “ ”抛出 操作已中止的错误

Page 19: Dynamic JS Loader

XMLHttpRequest脚本注入

无阻塞的脚本之XMLHttpRequest

Page 20: Dynamic JS Loader

XMLHttpRequest脚本注入 { 测试结果 }

无阻塞的脚本之XMLHttpRequest

兼容所有浏览器

下载 JS 代码但是不立刻执行

不能跨域!

Page 21: Dynamic JS Loader

… …似乎

• “ ”动态脚本元素 是一剂良药

• 简单的情况下可以轻松的解决问题

Page 22: Dynamic JS Loader

… …可是

现实往往比预期要复杂、更有挑战性

Page 23: Dynamic JS Loader

… …再思考

• 有两台服务器,其中一台备用。如何让客户能最快加载到 JS文件?

• 如何既能并发请求到 JS文件,又能让他们按照正确的顺序执行?

Page 24: Dynamic JS Loader

Ctrip的实际情况

域名 c-ctrip.com ctrip.com(备用)速度{speed}

稳定性{stability}

有两台服务器,速度和稳定性能如下

Page 25: Dynamic JS Loader

Ctrip的前端初步策略加载 c-ctrip站点的文件 fileN.js

1000ms后检测是否加载到

继续加载后续fileN.js

加载备用 ctrip站点的文件fileN_bak.js

是否页面JS全部加载完毕

Page 26: Dynamic JS Loader

Ctrip实现方案

方案一 ” ”先用动态脚本加载从 c-ctrip加载 file.js。 如果超时没有加载到,则从备用服务器 ctrip上获取

file_bak.js。

Page 27: Dynamic JS Loader

Ctrip实现方案 方案一 {测试结果 }

try {

在请求 file_ bak.js的同时, file.js也请求到了。}catch(error){

throw(

额外的 http请求

执行两遍 JS 函数)

}

Page 28: Dynamic JS Loader

Ctrip实现方案方案二

” ”先用动态脚本加载从 c-ctrip加载 file.js。

如果超时没有加载到,则删除这个 D OM, 从备用服务器 ctrip上获取file_ bak.js。

Page 29: Dynamic JS Loader

Ctrip实现方案 方案二 {测试结果 }

try {

if(浏览器是 Firefox){

即使删除脚本,浏览器不会停止请求}

}catch(error){

throw(

额外的 http请求

执行两遍 JS 函数)

}

Page 30: Dynamic JS Loader

Ctrip实现方案

方案三 优化方案二中的 Firefox。在 JS 文件头部先判断是否已经被加载 ;

如果加载过,则抛出一个错误,不再执行。

Page 31: Dynamic JS Loader

Ctrip实现方案 方案三 {测试结果 }

try {

多个文件同时加载 }catch(error){

throw(

额外的 http请求

不能保证 JS 的执行顺序)

}

Page 32: Dynamic JS Loader

• 方案四 使用 prefetch 预加载文件 不阻塞任何下载,并支持并行下载。

<link rel=“prefetch” href=“file.js”

onload=“registerScript()”>

Ctrip实现方案

Page 33: Dynamic JS Loader

Ctrip实现方案

方案四 {测试结果 }

try {

使用 prefetch预加载 }catch(error){

throw(

目前只支持 html5 ,未来可用。)

}

Page 34: Dynamic JS Loader

方案 5 (V5)

原则:将下载和执行分离

并行下载,不阻塞其他元素下载。

不阻塞页面渲染,在需要的时候才执行脚本。

Ctrip实现方案

Page 35: Dynamic JS Loader

方案五 new I mage or object 进行预加载

Ctrip实现方案

Page 36: Dynamic JS Loader

方案五 判断前一个依赖文件是否执行,以此来控制当前 JS的执行时间。

Ctrip实现方案

Page 37: Dynamic JS Loader

方案五 {测试结果 }

目前为止,业内完美的解决方案

Ctrip实现方案

Page 38: Dynamic JS Loader

让我们跟数据说说话

Page 39: Dynamic JS Loader

• 以下数据由 webpagetest.org测试得来

• 环境

Page 40: Dynamic JS Loader

发送请求截图

• 并行发送 js文件的请求,将文件先缓存下来

• 根据需要的 js执行顺序,确保执行顺序第一次加载

第二次加载

Page 41: Dynamic JS Loader

第一屏显示对比

Page 42: Dynamic JS Loader

页面加载对比

Before

After

Page 43: Dynamic JS Loader

Before

Page 44: Dynamic JS Loader

After

Page 45: Dynamic JS Loader

结论

• “JS下载和执行分离”带来了明显的变化

• 页面开始渲染时间从 7.4s降低到 1.3s• 页面加载完成时间从 8.8s降低到 4.3s

Page 46: Dynamic JS Loader

参考资料

• velocity-efws.ppt by Steve Souders

• “High Performance Javascript” by Nicbolas C. Zakas

• Labjs by Kyle Simpson

• Webpagetest.org

Page 47: Dynamic JS Loader

… …感谢

• Steve Souders的优化思想

• @nyanhan,@流光奕羽提供的思路和方案

• @ctrip前端开发 JS组

• @ 水漫三楼 @Jackie

Page 48: Dynamic JS Loader