執行模塊的機制大不同
-----------------------------------
因爲 RequireJS 是執行的 AMD 規範, 所以全部的依賴模塊都是先執行.
使用 RequireJS 默認定義模塊的方式, 在理解上會更清楚一些, 但我的仍是偏心 require('./mod1') 這樣的方式
define(['dep1', 'dep2'], function (dep1, dep2) {
//Define the module value by returning a value.
return function () {};
});
但願文章沒有誤人子弟, 謝謝
@Jaward華仔 的意見, 請你們多看評論, 評論更有料...
---------------------------------------------------------------------------
SeaJS對模塊的態度是懶執行, 而RequireJS對模塊的態度是預執行
不明白? 讓咱們來舉個例子
以下模塊經過SeaJS/RequireJS來加載, 執行結果會是怎樣?
define(function(require, exports, module) {
console.log('require module: main');
var mod1 = require('./mod1');
mod1.hello();
var mod2 = require('./mod2');
mod2.hello();
return {
hello: function() {
console.log('hello main');
}
};
});
猜猜看?
先試試SeaJS的執行結果
require module: main
require module: mod1
hello mod1
require module: mod2
hello mod2
hello main
|
很正常嘛, 我也是這麼想的...
|
再來是RequireJS的執行結果
require module: mod1
require module: mod2
require module: main
hello mod1
hello mod2
hello main
|
神馬狀況? 你他麼是在逗我嗎?
|
RequireJS你坑的我一滾啊, 這也就是爲何我不喜歡RequireJS的緣由, 坑隱藏得太深了.
終於明白
玉伯說的那句: "
RequireJS 是沒有明顯的 bug,SeaJS 是明顯沒有 bug"是什麼意思了
所以咱們得出結論(分別使用SeaJS 2.0.0和RequireJS 2.1.6進行測試)
-------------------------
SeaJS只會在真正須要使用(依賴)模塊時才執行該模塊
SeaJS是異步加載模塊的沒錯, 但執行模塊的順序也是嚴格按照模塊在代碼中出現(require)的順序, 這樣才更符合邏輯吧! 你說呢, RequireJS?
而RequireJS會先儘早地執行(依賴)模塊, 至關於全部的require都被提早了, 並且模塊執行的順序也不必定100%就是先mod1再mod2
所以你看到執行順序和你預想的徹底不同! 顫抖吧~ RequireJS!
詳細的代碼請參考
-------------------------
SeaJS測試加載/執行模塊
RequireJS測試加載/執行模塊
後記
-------
注意我這裏說的是執行(真正運行define中的代碼)模塊, 而非加載(load文件)模塊.
模塊的加載都是並行的, 沒有區別, 區別在於執行模塊的時機, 或者說是解析.
爲了說明阻塞的問題, 翠花上圖
|
SeaJS的懶執行
|
|
RequireJS的預執行
|
注意圖中巨大的pinyin-dict.js模塊, 取自
pinyin.js, 複製了N次後以增長它的"重量", 加強演示效果, 你們有興趣的話能夠親手試試.
能夠很明顯的看出RequireJS的作法是並行加載全部依賴的模塊, 並完成解析後, 再開始執行其餘代碼, 所以執行結果只會"停頓"1次, 完成整個過程是會比SeaJS要快.
而SeaJS同樣是並行加載全部依賴的模塊, 但不會當即執行模塊, 等到真正須要(require)的時候纔開始解析, 這裏耗費了時間, 由於這個特例中的模塊巨大, 所以形成"停頓"2次的現象, 這就是我所說的SeaJS中的"懶執行".
最後感謝你們的各類意見建議, 我這裏並無說SeaJS與RequireJS哪一個更好一些, 僅僅是爲了說明下他們的區別, 各類取捨請你們根據實際狀況來定, 但願能幫到你們.
牛人觀點:
1,
我我的感受requirejs更科學,全部依賴的模塊要先執行好。若是A模塊依賴B。當執行A中的某個操doSomething()後,再去依賴執行B模塊require('B');若是B模塊出錯了,doSomething的操做如何回滾?
不少語言中的import, include, useing都是先將導入的類或者模塊執行好。若是被導入的模塊都有問題,有錯誤,執行當前模塊有何意義?
總之載入的全部模塊,都是當前要使用的,爲何要動態的去執行?這個問題能夠總結爲模塊的載入執行是靜態仍是動態。若是是動態執行的話,那頁面的程序執行過程會受到當前模塊執行的影響。而正如樓主所言,動態執行整體時間上是比靜態一次執行要慢的。
樓主說requirejs是坑,是由於你還不太理解AMD「異步模塊」的定義,被依賴的模塊必須先於當前模塊執行,而沒有依賴關係的模塊,能夠沒 有前後。在樓主的例子中,假設mod1和mod2某天發生了依賴的話,好比在某個版本,mod1依賴了mod2(這是徹底有可能的),這個時候seajs 的懶執行會不會有問題?而requirejs是不會有問題,也不須要修改當前模塊。
在javascript這個天生異步的語言中,卻把模塊懶執行,這讓人很不理解。想像一下factory是個模塊工廠吧,而依賴 dependencies是工廠的原材料,在工廠進行生產的時候,是先把原材料一次性都在它本身的工廠里加工好,仍是把原材料的工廠搬到當前的 factory來何時須要,何時加工,哪一個總體時間效率更高?顯然是requirejs,requirejs是加載便可用的。爲了響應用戶的某個 操做,當前工廠正在進行生產,當發現須要某種原材料的時候,忽然要中止生產,去啓動原材料加工,這不是讓當前工廠很是焦燥嗎?
暫且不去理會這個吧,等ECMA規範中加入了模塊化的定義後,再看誰更合理吧。
2,
AMD 運行時核心思想是「Early Executing」,也就是提早執行依賴。這個好理解:
//main.js
define(['a', 'b'], function(A, B) {
//運行至此,a.js 和 b.js 已下載完成(運行於瀏覽器的 Loader 必須如此);
//A、B 兩個模塊已經執行完,直接可用(這是 AMD 的特性);
return function () {};
});
我的以爲,AMD 的這個特性有好有壞:
首先,儘早執行依賴能夠儘早發現錯誤。上面的代碼中,假如 a 模塊中拋異常,那麼 main.js 在調用 factory 方法以前必定會收到錯誤,factory 不會執行;若是按需執行依賴,結果是:1)沒有進入使用 a 模塊的分支時,不會發生錯誤;2)出錯時,main.js 的 factory 方法極可能執行了一半。
另外,儘早執行依賴一般能夠帶來更好的用戶體驗,也容易產生浪費。例如模塊 a 依賴了另一個須要異步加載數據的模塊 b,儘早執行 b 可讓等待時間更短,同時若是 b 最後沒被用到,帶寬和內存開銷就浪費了;這種場景下,按需執行依賴能夠避免浪費,可是帶來更長的等待時間。
我我的更傾向於 AMD 這種作法。舉一個不太恰當的例子:Chrome 和 Firefox 爲了更好的體驗,對於某些類型的文件,點擊下載地址後會詢問是否保存,這時候實際上已經開始了下載。有時候等了好久才點確認,會開心地發現文件已經下好; 若是點取消,瀏覽器會取消下載,已下載的部分就浪費了。
https://www.imququ.com/post/amd-simplified-commonjs-wrapping.html