码迷,mamicode.com
首页 > Web开发 > 详细

现代浏览器JS异步加载方案

时间:2015-07-26 08:39:09      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:

好,不说废话,要凌晨了我快点写完,关于JS加载阻塞之类的不做科普,本文也不讨论IE9以下的浏览器。

 

headjs:“异步、并行加载并按你的顺序执行”,这个是最符合广大码农需求的,只是它越来越臃肿,连CSS Respone什么的都加进去了,没必要那么复杂

Loadjs:今天刚刚出现在OSC首页本人疯狂测试后发现,如果需要并行加载就是乱序的(哪个JS先下载完就先执行谁),如果要顺序下载就不能并发,经测试是下载一个执行一个,每个JS文件之间有10ms的空隙(JS下载和加载时所有渲染操作都要暂停,连下载都不行)

还有一个不说了,那是给No-Backend的网站专用的,很庞大一库,功能抄复杂

 

综上所述,如果你在乎性能和代码质量,一个都不要用

然而这些库都解决了一个致命问题——内联JS的异步加载,这就很纠结了对吧

 

然而,在现代浏览器环境下,很多原来性能障碍都解决了,新的障碍又特么出来了

1)所有现代浏览器(IE9+),都有“JS预加载器”其实本质是“预下载”,在渲染DOM的同时把所有网页资源都下载好(JS、css、img等等)

2)关于并行下载呢,经测试,所有浏览器都可以同时下载10-20个资源文件,比原来2-6个多的多了,作为现代的JS加载器没必要考虑并行下载的问题

3)现在大部分码农都只是不用或者只用JQuery里面的一部分了吧,追求性能是必须的,当然随着项目越来越庞大,引入Angular,Ember之类的巨型框架也是没办法,下载慢到不担心,关键执行慢卡死在那里结果用户一直白屏

4)defer="defer"已被所有浏览器支持,只是只适用于外部JS,内联JS只在IE有效,这正是本文要解决的问题

5)因为JS MVC框架的模板问题,很多JS代码不得不写在HTML里以获得服务器模板引擎的渲染(我还没看见过谁渲染一遍JS的,当然node除外哈。。)

 

好,show code

因为Riot.js,Angular.js这类框架对JS文件的加载时间段有很高的要求,所以用他们做demo再合适不过

1)给所有的外部JS加上 defer="defer"

    <script src=‘riot.min.js‘ defer=‘defer‘></script>
    <script src=‘todo.js‘ defer=‘defer‘></script>

2)给内联JS封装一个DOMContentLoaded,现代浏览器都提供了100%这个事件,然而并没有封装。。。。不像window.load那样直接可用,把下面的代码放入一个外部JS,并且不要使用 defer="defer"

  //保存domReady的事件队列
eventQueue = [];
 
//判断DOM是否加载完毕
isReady = false;
 
//判断DOMReady是否绑定
isBind = false;
 
/*执行domReady()
 *
 *@param    {function}
 *@execute  将事件处理程序压入事件队列,并绑定DOMContentLoaded
 *          如果DOM加载已经完成,则立即执行
 *@caller
 */
function domReady(fn){
    if (isReady) {
        fn.call(window);
    }
    else{
        eventQueue.push(fn);
    };
 
    bindReady();
};
 
/*domReady事件绑定
 *
 *@param    null
 *@execute  浏览器通过addEvListener绑定DOMContentLoaded,包括ie9+
 *@caller   domReady()
 */
function bindReady(){
    if (isReady) return;
    if (isBind) return;
    isBind = true;
        document.addEventListener(‘DOMContentLoaded‘,execFn,false);
};
 
/*执行事件队列
 *
 *@param    null
 *@execute  循环执行队列中的事件处理程序
 *@caller   bindReady()
 */
function execFn(){
    if (!isReady) {
        isReady = true;
        for (var i = 0; i < eventQueue.length; i++) {
            eventQueue[i].call(window);
        };
        eventQueue = [];
    };
};

如果非要支持IE6-8,那这里有个完整的demo http://dengo.org/archives/1037

亲测表示这个比Jquery的document.ready快!

其实这个时候JQuery的document.ready是用不了的,因为JQ还没被加载呢,除非你不对JQ异步加载,这样异步加载的意义就不大了

3)对于内联JS代码,以后统一用 domReady(function(){  //   });包裹

//内联JS 1
domReady(function(){
      riot.mount(‘todo‘, {
      title: ‘I want to behave!‘,
      items: [
        { title: ‘Avoid excessive coffeine‘, done: true },
        { title: ‘Hidden item‘, hidden: true },
        { title: ‘Be less provocative‘ },
        { title: ‘Be nice to people‘ }
      ]
    })
});

这个domReady()可以调用多次,直接用就行

好吧我科普一下,这个DOMContentLoaded就是在DOM结构加载完就触发(就是chrome developer tools -> TimeLine 里的那根蓝线),而window.load是在整个页面全部加载完时触发(就是chrome developer tools -> TimeLine 里的那根红线,在用户看来就是小菊花不转的时候)

 

好这样就解决了所有问题,结论就是,如果你需要引入很多庞大的库,又不想过于影响页面的首次加载速度(白屏时间),这个方案适合所有网站,嗯,用吧。

本文按cc-署名-以相同方式共享传播

现代浏览器JS异步加载方案

标签:

原文地址:http://my.oschina.net/tenzing/blog/483748

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!