Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前端优化之js资源加载策略 #8

Open
kuitos opened this issue Aug 23, 2015 · 3 comments
Open

前端优化之js资源加载策略 #8

kuitos opened this issue Aug 23, 2015 · 3 comments

Comments

@kuitos
Copy link
Owner

kuitos commented Aug 23, 2015

前端优化之js资源加载策略

原文写于 2014-08-13

阅读这篇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 方式

看一下案例

这里有两个问题:

  1. h.js没有跟其他js一起并行下载,明显被阻塞了。
  2. 第二张图的ajax请求几乎是最后才触发的,但是这个请求是最关键所在,它会向后台拿数据然后渲染到前台。也就是说在他的相应回来之前,页面会一直出于无数据(用户看上去就好像没打开完成一样)状态,h.js是百度统计需要的js,并不是我们立即要用到的,理应在最后才加载。而查后台数据的ajax请求是页面渲染的关键,应该尽可能的在必需js加载完之后立即执行,这样至少页面看上去会打开快点(页面渲染的时间提前)。

基于这两个问题,我们的思路是这样的:

  1. 不必要的资源我们做延时载入,这里使用setTimeout,尽量使这些文件在所有必需请求完成之后进行,然后偷偷下载。
  2. 尽可能提前请求数据的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左右 资源请求不变,页面打开耗时 1.7s

关于ScriptLoader具体实现,没什么高科技,有兴趣同学可以看下代码:ScriptLoader

Ps:当页面耗时已经在2秒左右时,稳定提升100ms都是有难度的,这就好比110米栏选手跑进14秒容易,跑进13秒就很难了!

@TonyPythoneer
Copy link

看不到的圖了@@

@kuitos
Copy link
Owner Author

kuitos commented Dec 29, 2015

@TonyPythoneer 多谢提醒,已修复。图片较大可能需要点开才能看清

@mhxy13867806343
Copy link

学习了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants