瀏覽器加載js的阻塞與非阻塞

 這幾天因項目需求,要實現一系列的js文件加載的問題,因而,就按照常規思路寫了一通,悲催的是測試後發現問題重重;javascript

爲何會有這麼多問題,仔細想來仍是對瀏覽器加載js的原理理解不透,因而我翻閱了大量的資料和本身的一些實踐,總結出來如下的內容;html

一、js在瀏覽器中的阻塞java

  常規理解就是瀏覽器在加載js時候會阻塞瀏覽器的渲染操做,但頁面性能決定不但願咱們在加載js的時候影響頁面的渲染,因此咱們常常會把js文件放到body以前去加載。而不會把它放在head裏去阻塞頁面的渲染。那麼問題來了,若是咱們把js放在head裏,瀏覽器是怎麼去執行它的呢,是按順序加載仍是並行加載呢?跨域

其實在舊的瀏覽器下,都是按照前後順序來加載的,這就保證了加載的js依賴不會發生問題。可是新的瀏覽器已經開始容許並行加載js了,也就是說我能夠同時下載js文件,可是仍是前後順序執行文件的。瀏覽器

二、document.write 使用app

咱們通常會用document.write來生成一段廣告,常常這樣操做:document.write('<script id="posAD" type="text/javascript" src="http://192.168.3.107:888/control.js?platformcode=tcy&postioncode=A1&filecode=10030"><\/script>');dom

這樣操做也是阻塞的;有同窗就問了,你這是外聯js,那麼內鏈的呢,我也作過測試,同樣的,一樣會阻塞。異步

這樣使用的時候必定要記住,要確保他是在dom ready以前去執行,不然它將會從新渲染整個頁面。async

三、那麼如何實現非阻塞呢,那麼就須要動態加載js了,經過appendChild(script)這種方式去異步加載js了,其實還能夠用xhr對象來處理,可是這樣只能解決非跨域問題,跨域xhr就無能爲力了。還有一種辦法就是新瀏覽器的defer 和 async 屬性了,這樣你把它寫到head裏也不會阻塞瀏覽器的渲染了。post

 

因而在我明白上述的這樣東東以後,我簡單的實現一個動態加載js模塊:

    //loadJS模塊
    (function () {

      var loadJS = function (deps, callback) {
        if(typeof deps == 'string') {
          deps = [deps];
        }

        var len = deps.length;
        var   j = 0 ;
        var  fn = function (){
              j++;
              if(j == len) {
                callback.apply(window);
              }
        };

        for(var i = 0 ; i < deps.length ; i++) {
               _loadMod(deps[i],fn);       
        };
      };

      var _loadMod = function(url,fn) {
        var    head = document.head || document.getElementsByTagName('head')[0] || document.documentElement;
        var  script = document.createElement('script');
             script.type = 'text/javascript';
             script.charset = 'utf-8';
             script.async = true;
             script.src = url;
             script.onload = script.onreadystatechange = function() {
             if (!script.readyState || script.readyState in {'loaded': 1, 'complete': 1}) {
                    script.onload = script.onreadystatechange = null;
                    fn();
                    head.removeChild(script);
                    script = null;
                }
             }
             head.insertBefore(script, head.firstChild);
       } 

       window.loadJS = loadJS;

    })();

以上內容也是我這兩天初步終結出來的,有不對的地方還但願各位童鞋指正。

有興趣的還能夠參考這兩篇博客:http://www.w3cfuns.com/blog-5443287-5401014.html 或則 http://www.cnblogs.com/hongcaomao/archive/2012/03/27/javascript_loadad.html

相關文章
相關標籤/搜索