我的模塊加載系統 v17


本版本的重要更新是完全實現AMD規范。整個框架根據此新加載器重寫,因此可以方便調用老外用AMD規范寫好的JS庫了.

  • 日志打印可以通過設置$.core.level排除某些不重要的日志打印。
  • 添加config方法來設置框架的一些重要信息或對模塊進行別名。
  • 在VS系列實現智能提示。

有關本模塊加載系統的使用,可以到這里詳看教程.新加載器是同時支持AMD與玉伯搞的seajs的CMD.如果你在模塊定義中的回調帶有"require","exports","modules"中的任兩個,加載器就視為CMD.不過無視是AMD與CMD,函數里面require, modules, exports都是可用的,完全可以像node.js這樣加載模塊.

有關require方法的模塊標識,可以見這里

有關為什么要用AMD來管理我們的腳本,我想做過一些大項目的人應該心中有數,這不是一個合並JS所能取替的,詳見此文


下面揭載我的加載器的運作機理,姑且從一個沒有依賴的模塊着手,比如

            $.require("$lang_fix", function(){
                console.log("xxxxxxxxxxxxxx")
            })

不用說,進入$.require(希望大家看這東西時,打開源碼對照着看。)

 String(list).replace( $.rword, function(el){

  })

el  = "$lang_fix"

進入Module._resolveFilename


url = $.core.base + el + ".js"

初次加載,肯定沒有在modules中注冊, modules[url]為undefined

於是進入 loadJS( url, id );

  • 創建一個iframe,
  • 在第一個script節點 用nick, Ns, nick分別保存url, $, innerDefine
  • 在第二個script節點 用url去加載目標節點

第二個節點視情況不同分別綁定onreadystatechange, onload, onerror

值得注意的是我們在注冊模塊時state還是為undefined,它會在innerDefine中修改state。

然后我們通過iframe中的script加載模塊,而模塊一般是這樣的格式
define("lang_fix", function( ){
  //==========略============
})

這里的define實質上是innerDefine

innerDefine里面做了幾個很重要的事情(我們現在只需看第一,第二)

  1. 第一個事情把lang_fix這第一個參數換掉,換成nick, nick就是加載它的那個script的src。
  2. 第二個事情是將它對應的模塊的狀態改為1,也是modules[url].state = 1。
  3. 第三個事情是$, exports, require, module等對象強塞進模塊工廠
  4. 第四個事情是轉交真正的$.define去處理

在第二事情中,我們將模塊的狀態修改了,於是節點執行onreadystatechange/onload時

if(/loaded|complete|undefined/i.test(this.readyState) }{
    Ns._checkDeps();
     Ns._checkFail(self.document, nick);
}

Ns._checkFail發揮效力

_checkFail : function(  doc, id, error ){
    doc && (doc.ok = 1);
    if( error || !modules[ id ].state ){
         this.log("Failed to load [[ "+id+" ]]"+modules[ id ].state);
    }
},

如果是死鏈,那無法調用define函數,也就無法調用innerDefine,狀態為undefine

!modules[ id ].state == true,於是打印錯誤日志,當然以后我們討論一下,是不是該throw

如果在舊式opera,它是會無法進入onreadystatechange, onload, onerror任一回調

在_checkFail中,我們會修復doc.ok = 1,那么在iframe中onload中我們檢測doc.ok不等於1時,

就在_checkFail傳入第三個參數true,讓它打印錯誤日志

如果在FF,chrome, IE9,它們就會進入onerror回調,那里的調用代碼中


Ns._checkFail(self.document, nick, true)

因此也順利檢測到死鏈。

反正只要加載失敗,我們就立即把對應iframe移出DOM樹!

好了,如果成功加載,我們就通過innerDefine到達$.define,並也把對應iframe移出DOM樹

$.define干了如下幾個事情

  1. 第一個事情,檢測第二個參數是否為布爾,是說明其是補丁模塊,如果布爾值為true,說明這個補丁模塊對這個瀏覽器是沒有用的,直接return,不執行它的模塊工廠了。如果為false,比如IE6,補丁模塊對它總是有用,先去掉此參數,繼續往下執行。
  2. 第二個事情,檢測參數個數,如果只有兩個,說明只有模塊名與模塊的回調(亦有可能不是回調),那么我們插入一個空數組作為依賴列表
  3. 第三個就是檢測第三個參數是否為函數,不是函數,比如說是個對象,我們要將它塞入一個函數

比如


define({
  aaa:2
})

經上面幾次轉換,依次變為


define("http://xxxxxxx/aa.js",{
  aaa:2
});
//---->
define("http://xxxxxxx/aa.js" ,[],{
  aaa:2
});

//---->
define("http://xxxxxxx/aa.js" ,[], function(){
 return {
    aaa:2
  }
});

//---->
$.require([], function(){
 return {
    aaa:2
  }
}), "http://xxxxxxx/aa.js")

最后我們將參數的順序重排一下,再次調用$.require

 //0,1,2 --> 1,2,0
 this.require( args[1], args[2], parent );

由於lang_fix是沒有依賴的,因此dn === cn 相當於 0 == 0,執行install( id, args, factory );

install簡而言之是將模塊工廠執行,將state改為2。

我們還需要注意一下,我們每次調用$.require或加載一個腳本時都執行_checkDeps方法。

當lang_fix的狀態改為2后



 $.require("$lang_fix", function(){
      console.log("xxxxxxxxxxxxxx")
 })

這個回調也將執行!

控制台打印xxxxxxxxxxxxxxxx

源碼位於這里


免責聲明!

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



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