seaJS 模組載入過程分析

來源:互聯網
上載者:User

標籤:style   blog   http   java   使用   檔案   io   for   

先看一個seajs的官方example,  以下以seajs.use(‘main‘)為例, 解析載入mod main的過程

//app.htmlseajs.use("main"); //main.jsdefine(function(require) {  var Spinning = require(‘./spinning‘);  var s = new Spinning(‘#container‘);  s.render();}); //spinning.jsdefine(function(require, exports, module) {    var $ = require(‘jquery‘);     function Spinning(container) {        this.container = $(container);        this.icons = this.container.children();        this.spinnings = [];    }    module.exports = Spinning;    function random(x) { return Math.random() * x };});
module在載入過程中的幾種狀態
Module.STATUS = {  // 1 - The `module.uri` is being fetched  FETCHING: 1,  // 2 - The meta data has been saved to cachedMods  SAVED: 2,  // 3 - The `module.dependencies` are being loaded  LOADING: 3,  // 4 - The module are ready to execute  LOADED: 4,  // 5 - The module is being executed  EXECUTING: 5,  // 6 - The `module.exports` is available  EXECUTED: 6}
每個mod在載入過程中會維護一些自身的重要屬性,如
  • dependencies: 模組的直接依賴

  • _remain: 預設為當前mod的dependencies的length,用來加鎖,只有當自身直接依賴的所有模組都載入完畢,即狀態為LOADED的時候, _remain變為0,此時觸發當前mod的onload, 通知直接依賴它的模組。

  • _waiting: 儲存直接依賴它的模組表,這個屬性,使得模組之間建立起依賴關係鏈, 對模組載入完成後的通知機制非常重要。

  • factory: 為define(id, deps, factory) module定義中的參數

  • callback: 為使用use時產生的module的特有屬性, 這個在喚醒機制的時候比較有用

圖解seajs.use(‘main‘), 模組的載入過程如下:

 

 

執行過程分析:

使用use調用,會自動構建一個module,id為當前文檔中use的次數和use進行的拼接, 如_use_0, 一般它會成為依賴鏈的源頭。

模組載入完成後,先觸發JS檔案內容執行,此時define函數被執行, 完成該module的兩個重要屬性dependencies & _waiting的初始化。

模組載入完成後,觸發onload事件,如當前模組有dependencies,進入並行載入流程。 或者當發現當前模組的dependencies全部載入完畢或者為空白時, 根據_waiting來逐級喚醒,執行module的callback,由於只有使用use調用的時候才會為mod添加callback屬性,所以這個過程一般會向上索引到依賴鏈的源頭,在上述代碼執行個體中,這個依賴鏈大概可以描述如下:

 

執行use函數建立的module 會給添加一個自訂的callback函數, 因為通常作為依賴鏈的源頭, 需要從它開始計算和它有直接關係的dependencies的exports, 計算過程相當於將依賴的module的factory函數依次執行一遍,如在執行中發現代碼中有requrie的情況,如main.js 檔案中的 var Spinning = require(‘./spinning‘),再執行一下require 的module。

代碼如下:

mod.callback = function() {    var exports = []    var uris = mod.resolve()    for (var i = 0, len = uris.length; i < len; i++) {      exports[i] = cachedMods[uris[i]].exec()    }    if (callback) {      callback.apply(global, exports)    }    delete mod.callback}

計算好exports後, 會用exports作為參數在調用當前module原來的callback, module執行完畢。

和requirejs的最大區別

最大的區別就是seajs是模組載入和模組執行分離, 而requirejs是載入完畢後,會提前計算好module的exports; 在factory 的FunctionBody中的require(‘xxx‘), 只是直接擷取計算好的module xxx 的 exports 而已。

 

總結

看完seajs和requirejs的模組載入過程, 對指令碼動態載入有了更深入的理解, 在代碼的設計上, 通過使用_waiting來維護一個依賴關係鏈,執行的時候依次向上回溯,找到有callback屬性的mod開始執行, 就讓本來複雜的依賴關係管理變得簡單,  將代碼載入和執行分離有好處也會壞處,這個網上也有很多討論,就不展開描述, 總之還是覺得值得一看吧。

 

end

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.