Dynamic JS Loader
-
Upload
feifeipan -
Category
Technology
-
view
1.314 -
download
4
Transcript of Dynamic JS Loader
以下人群请勿阅读此系列 PPT
• 输入地址, 3秒之后窗口仍然空白一片,但没有感觉任何不适
• 不相信优化网站性能会带来更多的效益• 不认为页面速度提升能够带来客户满意度提升• 压根就不认为优化网站性能可以改变命运
… …思考
我们真的认为性能很重要吗?
… …发现
• 亚马逊发现,网站每慢 0.1秒等于丢失 600万美元的销售额。
• Google则发现,网页载入慢 0.5秒会导致20%的用户流失。
• Ctrip发现了吗?
… …思考
我们怎么引用 JS文件?
曾经(或现在)
…总是认为
随便找个地儿放一下JS,只要页面不报错就行啦
!
… …结果总是
• 曾经的痛
… …结果总是
为啥总是空白呢?空白还是空白 !!
… …因为
• 浏览器在解析到 <body>之前,不会渲染页面任何部分。
• 无论是内嵌还是外链,页面的下载和渲染都必须停下来等待脚本执行完成。
解决方案
• 将脚本放在底部• 减少脚本文件的大小• 限制 HTTP请求数
… …思考
JS真的需要在页面渲染的时候一起加载吗?
JS可以在需要的时候才加载吗?
JS可以先缓存好,等需要的时候再执行吗?
无阻塞脚本
在页面加载完成之后才加载 Javascript代码
无阻塞的脚本之延迟脚本
• 延迟的脚本
<script src=‘file.js’ defer></script>
defer 表明该脚本不会修改 DOM, 因此能安全地延迟执行。
无阻塞的脚本之延迟脚本
延迟的脚本 { 测试结果 }
注 : firefox3.6不支持 defer属性
只有 I E6.0+ 和 Firefox3.5 支持,其余浏览器均不支持
动态脚本元素
无阻塞的脚本之动态脚本元素
在页面中创建脚本节点,并添加到 D OM 中
动态脚本元素
无阻塞的脚本之动态脚本元素
可以实时监听到加载结束,添加回调函数
动态脚本元素 { 测试结果 }
无阻塞的脚本之动态脚本元素
• 无论何时启动下载,文件的下载和执行过程不会阻塞页面其他进程。
注:加在 head中比在 body中要可靠,防止 I E “ ”抛出 操作已中止的错误
XMLHttpRequest脚本注入
无阻塞的脚本之XMLHttpRequest
XMLHttpRequest脚本注入 { 测试结果 }
无阻塞的脚本之XMLHttpRequest
兼容所有浏览器
下载 JS 代码但是不立刻执行
不能跨域!
… …似乎
• “ ”动态脚本元素 是一剂良药
• 简单的情况下可以轻松的解决问题
… …可是
现实往往比预期要复杂、更有挑战性
… …再思考
• 有两台服务器,其中一台备用。如何让客户能最快加载到 JS文件?
• 如何既能并发请求到 JS文件,又能让他们按照正确的顺序执行?
Ctrip的实际情况
域名 c-ctrip.com ctrip.com(备用)速度{speed}
稳定性{stability}
有两台服务器,速度和稳定性能如下
Ctrip的前端初步策略加载 c-ctrip站点的文件 fileN.js
1000ms后检测是否加载到
继续加载后续fileN.js
加载备用 ctrip站点的文件fileN_bak.js
是否页面JS全部加载完毕
否
是
否
Ctrip实现方案
方案一 ” ”先用动态脚本加载从 c-ctrip加载 file.js。 如果超时没有加载到,则从备用服务器 ctrip上获取
file_bak.js。
Ctrip实现方案 方案一 {测试结果 }
try {
在请求 file_ bak.js的同时, file.js也请求到了。}catch(error){
throw(
额外的 http请求
执行两遍 JS 函数)
}
Ctrip实现方案方案二
” ”先用动态脚本加载从 c-ctrip加载 file.js。
如果超时没有加载到,则删除这个 D OM, 从备用服务器 ctrip上获取file_ bak.js。
Ctrip实现方案 方案二 {测试结果 }
try {
if(浏览器是 Firefox){
即使删除脚本,浏览器不会停止请求}
}catch(error){
throw(
额外的 http请求
执行两遍 JS 函数)
}
Ctrip实现方案
方案三 优化方案二中的 Firefox。在 JS 文件头部先判断是否已经被加载 ;
如果加载过,则抛出一个错误,不再执行。
Ctrip实现方案 方案三 {测试结果 }
try {
多个文件同时加载 }catch(error){
throw(
额外的 http请求
不能保证 JS 的执行顺序)
}
• 方案四 使用 prefetch 预加载文件 不阻塞任何下载,并支持并行下载。
<link rel=“prefetch” href=“file.js”
onload=“registerScript()”>
Ctrip实现方案
Ctrip实现方案
方案四 {测试结果 }
try {
使用 prefetch预加载 }catch(error){
throw(
目前只支持 html5 ,未来可用。)
}
方案 5 (V5)
原则:将下载和执行分离
并行下载,不阻塞其他元素下载。
不阻塞页面渲染,在需要的时候才执行脚本。
Ctrip实现方案
方案五 new I mage or object 进行预加载
Ctrip实现方案
方案五 判断前一个依赖文件是否执行,以此来控制当前 JS的执行时间。
Ctrip实现方案
方案五 {测试结果 }
目前为止,业内完美的解决方案
Ctrip实现方案
让我们跟数据说说话
• 以下数据由 webpagetest.org测试得来
• 环境
发送请求截图
• 并行发送 js文件的请求,将文件先缓存下来
• 根据需要的 js执行顺序,确保执行顺序第一次加载
第二次加载
第一屏显示对比
页面加载对比
Before
After
Before
After
结论
• “JS下载和执行分离”带来了明显的变化
• 页面开始渲染时间从 7.4s降低到 1.3s• 页面加载完成时间从 8.8s降低到 4.3s
参考资料
• velocity-efws.ppt by Steve Souders
• “High Performance Javascript” by Nicbolas C. Zakas
• Labjs by Kyle Simpson
• Webpagetest.org
… …感谢
• Steve Souders的优化思想
• @nyanhan,@流光奕羽提供的思路和方案
• @ctrip前端开发 JS组
• @ 水漫三楼 @Jackie