seajs3.0模塊加載原理及源碼註釋

    由於前端業務的複雜,導致前端開發的複雜度日益遞增,所以有必要對前端進行模塊化劃分並進行模塊的依賴管理。現在前端模塊化主要有COMMONJS、AMD、CMD等標準。目前國內的 seajs 還算比較流行,它是基於CMD標準的,鑑於學習的目的,花了些時間研究了下seajs3.0 的源碼,這裏主要分享一下 模塊依賴加載的原理。 同時附上一份簡單的源碼註解。(作者水平有限,時間也有限,僅供參考,有任何說得不對的地方,大家可以指出共同學習探討)

    建議閱讀的朋友自己也看過 seajs3.0 的源碼,這樣纔不會覺得本文雲裏霧裏。 或者直接到本文最後面下載 seajs3.0註釋源碼

    seajs的模塊加載,是最核心、最複雜的一個模塊了,作者把模塊的狀態分爲了7種,實際上,最開始創建時模塊狀態爲0,相當於有8種狀態了。

    模塊加載要解決的一個核心問題是依賴的問題,比如,我們使用入口方法: use('main.js'),  main.js 依賴 A和B,A依賴C,B依賴D,那麼問題來了,什麼時候可以執行     main.js中的內容呢?


    我們都知道,當A、B、C、D這四個模塊加載並執行後便可以執行 main.js,而A、B、C、D的執行也是有順序的,這一切都交由模塊依賴管理來解決。
  
    模塊會涉及到幾個核心的方法:
    use   入口方法
    fetch 抓取模塊js,實際上註冊了onload回調事件,並在load中調用請求資源的接口去真正獲取資源
    load  當一個模塊加載並把元數據保存到cachedMods後會執行此方法(這時候模塊已經知道依賴了哪些模塊)
    pass  涉及到依賴處理最核心的 模塊傳遞問題和remain計數
    exec  執行模塊 factory
    define 即爲模塊js中的define方法
    save   保存模塊meta data 到 cachedMods
    get   獲取緩存中的Module實例


  
    下面講一個小縮影看看一切是如何進行的:


    當執行 use('main.js')的時候, seajs創建了一個匿名模塊(即Module實例,我們先稱爲初始模塊),它默認已經加載好了,接着,它會調用它的load方法。load方法會遍歷依賴的模塊(即main模塊),同時傳遞初始模塊實例給main模塊,初始模塊實例有個remain變量,用於表示還差加載多少模塊便可以執行了。


    到這裏,remain的值顯然爲1。


    接着,初始模塊的load方法會去fetch(main),然後獲取 main.js,執行 main.js中的define方法,並解析main.js中的依賴A和B,當做完這一步之後,main模塊的load方法得到了執行,它同樣會把 初始模塊實例 傳遞給 A和B,這時候remain爲3,但是,這時候main模塊已經執行完回調了,所以其實只要A和B模塊都加載好了,便可以執行 初始模塊了,所以最後 remain爲2。


    接下來,同樣去 fetch A和B,然後執行 A和B的 define,得到依賴C和D,同時把初始模塊實例 傳遞給C和D,由於A和B回調也已經執行完畢,所以這時候 remain=2+2-2,依賴爲2,只要C和D模塊都加載好了,那麼初始模塊便可以執行。當C和D加載完成後,由於它們沒有依賴了,所以不再需要傳遞 初始模塊實例,當C加載完成後,由於C沒有依賴,它會觸發 onload方法,把remain變爲1,D加載完成後,也沒有依賴,它也會觸發 onload方法,把 remain變爲0,這時候一旦發現 remain=0,便會執行 use的時候註冊的一個回調事件,表示可以執行匿名初始模塊了
  
    其實,這時候,main、A、B、C、D模塊中的 factory還沒有真正得到執行,只是執行了define而已,use註冊的回調會依次執行依賴模塊的exec方法。
  
    整個流程最核心的就是對於 remain 的控制, 傳遞的 初始模塊實例 存在 模塊內部的_entry中,而 remain存儲在初始模塊實例中。


    整個模塊依賴加載及處理最核心的理解的就是remain了,當remain=0,便會執行初始模塊了,這時候所有依賴都解析好,加載好了,所以不需要考慮加載的問題,直接從main.js開始執行便是了,當遇到 require('A')的時候,會先執行A的factory得到exports,所以總體可以認爲是 異步加載,但只有等到全部加載完之後纔會去執行,除非使用了  require.async,相當於又使用了其它的 use。
  
    這裏假定  A先於B加載, C先於D加載
    onRequest 爲綁定在script節點上的onload事件,下圖爲一個簡要的remain變量示意圖
  



                                
    A和B在執行load方法前後,remain不變是由於A加載後,remain-1,但依賴了C,又加了1,B同理。                               
    C和D能夠執行 Module.onload是由於它們都沒有依賴。
    當D執行了 D.onload之後,發現remain爲0,執行 匿名模塊的callback,回調中開始依次執行各個模塊,因爲這時候所有模塊都已經加載好了。                                  
 

    以上便爲實現模塊依賴加載的原理。

    最後附上筆者閱讀源碼時的一些註釋,一份帶註釋的 seajs3.0 源碼。 詳見 : seajs3.0註釋源碼下載


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章