javascript動態加載三


先做兩個鏈接:

javascript動態加載

javascript動態加載二

之前兩篇都介紹了,通過動態加載JS文件或者說JS模塊,是怎么一步一步實現。

首先是通過同步策略來實現模塊加載與回調函數之間進行分離,接着是通過異步策略來實現模塊加載與回調函數之間進行分離。

這一篇,主要是為了說說怎么優化異步策略,並且實現了隨意加載(非任意順序加載模塊),頁面Ready之后加載文件。先接一下上一篇遺留下來的問題

1、頁面Ready之后進行加載

2、隨意添加模塊 進行加載

看第一個問題,這個問題其實還是比較簡單的,主要是監聽頁面的DOMContentLoaded事件,這里就不多講解,網絡上搜索,一堆答案,直接上代碼。

    Using.ready = function(callback){
        readyList.push(callback);
        
        if(document.addEventListener){
            document.addEventListener("DOMContentLoaded",_ready,false);
            return;
        }
        // for IE
        var domReady = function(){
            try{
                document.documentElement.doScroll("left");
                _ready();
            }catch(ex){
                setTimeout(domReady,1);
                return;
            }
        }
        domReady();
    }

這一段代碼中最難以理解的應該就是

document.documentElement.doScroll("left");

這里其實是IE的頁面加載完畢事件,簡單說就是IE里面標簽加載完畢之后,是可以操作Scroll的,那就根據此原理來判斷IE中頁面是否加載完畢。

里面有一個_ready函數,這個函數就是用來做頁面加載完畢之后執行所有加載的函數。貼一下代碼

(編輯一下這一段:頁面加載完畢Ready函數並不是我們思想中所認為的原生JS的window.onload,簡單說只是頁面中DOM結構的加載完畢,具體信息,可自行百度google之)

var readyList = [];    
var _ready = function(){
        while(readyList.length > 0){
            var func = readyList.shift();
            func();
        }
        document.removeEventListener("DOMContentLoaded",_ready,false);
    }

下面就是本博文的重點了。還是先看一下代碼

    Using.asyn = function(callback){
        asynQueue.push(callback);
        if(!_execAsyn.isRunning){
            _execAsyn();
        }
    }

還是通知Using要加載所需要的模塊了,只不過里面加入了一個asynQueue數組和_execAsyn函數,他們的作用分別是

asynQueue是用來保存異步加載之后要回調的函數,沒什么好解釋的,是一個數組,可以理解為創建了一個函數的隊列

_execAsyn是用來執行保存的那些回調函數的,即將所保存的函數逐一執行。看一下代碼,代碼中對每行的作用都進行了注釋

    var _execAsyn = function(){
        // 創建一個變量來緩存需要執行的函數
        var func = null;
        // 如果隊列中還有未執行的函數 則進行執行操作
        if(asynQueue.length > 0){
            // 將_execAsyn函數修改為運行狀態
            _execAsyn.isRunning = true;
            // 得到隊列中第一個需要執行的函數
            func = asynQueue.shift();
            // 調用異步加載模塊Using.fn.script函數 並傳入加載完畢之后需要執行的回調函數
            Using.fn.script(function(){
                // 當前需要執行的函數
                func();
                // 迭代_execAsyn 直到隊列中沒有需要執行的函數
                _execAsyn();
            });
        // 若隊列中沒有需要執行的函數
        }else{
            // 則將_execAsyn運行狀態改為false
            _execAsyn.isRunning = false;
        }
    }

這個函數,解釋起來沒什么特別的,說白了就是一個一個的執行需要執行的函數。那么,唯一需要注意的就是為什么操作隊列的時候沒有采用循環,而是使用迭代。那原因就是

1、隊列中隨時可能有新的函數需要執行,采用循環的話,可能執行不到最新的函數,因為函數總是插入到隊列的尾部

2、 Using.fn.script是異步的,如果是循環的話,當前函數還沒有執行完,可能下一個函數就已經進入了執行狀態。那么,本身來說,同時執行幾個函數,速率上可能會更高,為什么這里還要限制其多個函數並行呢?原因也很簡單,因為每一次執行隊列中的函數,可能都需要加載相應的模塊,那么如果剛好有兩個或者多個依賴相同模塊的函數需要執行,而且並行執行,就可能出現同一個模塊加載多次,並可能造成后續的函數執行不了,出現異常。

整個UsingJS的核心部分就這些。在其中我加入了Using.Class.create函數,這個函數在javascript動態加載文章的末尾有提到。

最后看一下頁面使用情況:

<script type="text/javascript" src="js/using-0.4.2.min.js"></script>
<script type="text/javascript">
Using("jq");
Using("UserView");
Using("jq");

Using.ready(function(){
    Using.asyn(function(){
        $("#panel").click(function(){
            alert("by jquery");
        });
    });
});
Using.ready(function(){
    Using("Http");
    Using.asyn(function(){
        var http = new Using.Modules.Http();
        http.set("xxx");
        http.show();
    });
    Using.asyn(function(){
        var h = new Using.Modules.Http();
        h.set("ooo");
        h.show();
    });
    Using("jq");
    Using.asyn(function(){
        $("#panel").click(function(){
            alert("loaded jquery");
        });
    });
});
</script>

這個一段代碼,刻意進行重復加載,多次Ready事件和Ready之后進行Using導包。

有一個特別需要注意的地方

    Using("Http");
    Using.asyn(function(){
        var http = new Using.Modules.Http();
        http.set("xxx");
        http.show();
    });
    // 假如在這個地方使用
    // var ht = new Using.Modules.Http();
    // 是會報Using.Modules.Http不是一個constructor
    // 原因就是
    // 任何操作都是異步的,當執行此句時Using("Http")這個模塊載入可能還沒有完成
    // 這一點是仲謀給多個朋友進行使用時會犯的錯誤 總以為導包之后 萬事大吉
    // 是的 本身應該是這樣 導包之后 在任何地方都可以隨意引用
    // 但是總得有個前提吧 那就是模塊得加載完畢
    // 所以 還請將所有的代碼都寫在Using.asyn之內
    Using.asyn(function(){
        var h = new Using.Modules.Http();
        h.set("ooo");
        h.show();
    });

UsingJS下載(我只開了一個360的雲盤 哈哈 簡單嘛 呵呵 以本人的技術 還不至於去開一個github來 練習練習再說)

PS:希望下載的朋友 發現問題或者有更好的想法 提交於我 可以直接留言或者郵件我(sunjiawei1986@163.com) 謝謝

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM