前端优化之js资源加载策略
原文写于 2014-08-13 https://github.com/kuitos/kuitos.github.io/issues/8
阅读这篇blog之前,请先看下这本书:高性能网站建设进阶指南,里面详细的讲解了现今流行的几种异步脚本加载方案(不过里面一些结论不能盲目相信,实践之前请手动验证一下,毕竟浏览器实现日新月异)
不过还是先简单介绍下两种最常用的动态加载js资源的方案:
document.write方式
function outerHTML (node) { // if IE, Chrome take the internal method otherwise build one return node.outerHTML || (function (n) { var div = document.createElement('div'), h; div.appendChild(n); h = div.innerHTML; div = null; return h; })(node); }; document.write(outerHTML(el));
script dom element方式
document.getElementsByTagName('head')[0].appendChild(el);
两种方式的差异在这里
是否并行下载 | 执行是否保证顺序 |
---|---|
doc write | 是 |
script dom element | 是 |
差别只在于,script dom element 的策略是并行下载且谁先下完执行谁,不根据你script标签的顺序加载,真正的异步。
因此我们可以有个基础的认识,就是当前页面一定会用到的js,我们采用doc write方式去加载,而用不到的js就采用script dom element 方式
看一下案例
这里有两个问题:
- h.js没有跟其他js一起并行下载,明显被阻塞了。
- 第二张图的ajax请求几乎是最后才触发的,但是这个请求是最关键所在,它会向后台拿数据然后渲染到前台。也就是说在他的相应回来之前,页面会一直出于无数据(用户看上去就好像没打开完成一样)状态,h.js是百度统计需要的js,并不是我们立即要用到的,理应在最后才加载。而查后台数据的ajax请求是页面渲染的关键,应该尽可能的在必需js加载完之后立即执行,这样至少页面看上去会打开快点(页面渲染的时间提前)。
基于这两个问题,我们的思路是这样的:
- 不必要的资源我们做延时载入,这里使用setTimeout,尽量使这些文件在所有必需请求完成之后进行,然后偷偷下载。
- 尽可能提前请求数据的ajax.
这里需要提到一点知识,就是javascript是单线程的,也就是说如果有一个js在执行占用了线程,那么其他js就不能获得执行的机会,必须等待前一个执行完毕。
基于这个事实,采用setTimeout将不需要首页加载的js延时到最后执行,避免去跟主js抢占线程是最合适且最简单的方案。(不采用按需加载的方案是有综合考虑的,如压缩、代价、耗时等,因情况而定,具体可以私聊)
优化后的部分代码:
<script>
(function (window, ScriptLoader) {
ScriptLoader.addScriptsSync(["content.base.min.js", "content.app.min.js"]);
})(window, window.ScriptLoader);
</script>
<!--不需要立即加载的延迟脚本放这里-->
<script>
(function (ScriptLoader) {
ScriptLoader.addScriptAsyncDelayed(["content.lib.min.js",
(("https:" == document.location.protocol) ? "https://" : "http://") + "hm.baidu.com/h.js?30219399d7b243256f05f99e96aadb68"], null);
})(window.ScriptLoader);
</script>
看下效果:
可以看到请求数据的ajax被提前了,有了数据页面会立即渲染更新,所以这里页面展示完全的时间在 1.7s左右,优化前在2.5s左右。
content.lib.min.js和h.js作为首页不会立即用到的东西,在最后才做加载且下载是并行的。
汇总一下优化历程
js/css简单压缩合并 | 服务器开启gzip | 文中优化策略 |
---|---|---|
优化前 | 请求数 70+,资源总大小2M左右,页面打开耗时5s+ | 请求数 20+,资源总大小1.2M,页面打开耗时3s左右 |
优化后 | 请求数 20+,资源总大小1.2M,页面打开耗时3s左右 | 请求数 20+,资源总大小350K,页面打开耗时2.5s左右 |
关于ScriptLoader具体实现,没什么高科技,有兴趣同学可以看下代码:ScriptLoader
Ps:当页面耗时已经在2秒左右时,稳定提升100ms都是有难度的,这就好比110米栏选手跑进14秒容易,跑进13秒就很难了!