前端模塊化開發

js模塊化開發的價值

前端模塊化開發的價值

通過 exports暴露接口。這意味著不需要命名空間了,更不需要全局變量。這是一種徹底的命名沖突解決方案。
通過 require引入依賴。這可以讓依賴內置,開發者只需關心當前模塊的依賴,其他事情 Sea.js 都會自動處理好。對模塊開發者來說,這是一種很好的 關注度分離,能讓程序員更多地享受編碼的樂趣。

除了解決命名沖突和依賴管理,使用 Sea.js 進行模塊化開發還可以帶來很多好處:

模塊的版本管理。通過別名等配置,配合構建工具,可以比較輕松地實現模塊的版本管理。
提高可維護性。模塊化可以讓每個文件的職責單一,非常有利于代碼的維護。Sea.js 還提供了 nocache、debug 等插件,擁有在線調試等功能,能比較明顯地提升效率。
前端性能優化。Sea.js 通過異步加載模塊,這對頁面性能非常有益。Sea.js 還提供了 combo、flush 等插件,配合服務端,可以很好地對頁面性能進行調優。
跨環境共享模塊。CMD 模塊定義規范與 Node.js 的模塊規范非常相近。通過 Sea.js 的 Node.js 版本,可以很方便實現模塊的跨服務器和瀏覽器共享。

模塊化開發并不是新鮮事物,但在 Web 領域,前端開發是新生崗位,一直處于比較原始的刀耕火種時代。直到最近兩三年,隨著 Dojo、YUI3、Node.js 等社區的推廣和流行,前端的模塊化開發理念才逐步深入人心。

前端的模塊化構建可分為兩大類。一類是以 Dojo、YUI3、國內的 KISSY 等類庫為代表的大教堂模式。在大教堂模式下,所有組件都是顆粒化、模塊化的,各組件之間層層分級、環環相扣。另一類是以 jQuery、RequireJS、國內的 Sea.js、OzJS 等類庫為基礎的集市模式。在集市模式下,所有組件彼此獨立、職責單一,各組件通過組合松耦合在一起,協同完成開發。

這兩類模塊化構建方式各有應用場景。從長遠來看,小而美更具備寬容性和競爭力,更能形成有活力的生態圈。

總之,模塊化能給前端開發帶來很多好處。如果你還沒有嘗試,不妨從試用 Sea.js 開始。

requireJS實現原理

requireJS實現原理研究1
流程

  1. 我們在使用requireJS時,都會把所有的js交給requireJS來管理,也就是我們的頁面上只引入一個require.js,把data-main指向我們的main.js。
  2. 通過我們在main.js里面定義的require方法或者define方法,requireJS會把這些依賴和回調方法都用一個數據結構保存起來。
  3. 當頁面加載時,requireJS會根據這些依賴預先把需要的js通過document.createElement的方法引入到dom中,這樣,被引入dom中的script便會運行。
  4. 由于我們依賴的js也是要按照requireJS的規范來寫的,所以他們也會有define或者require方法,同樣類似第二步這樣循環向上查找依賴,同樣會把他們村起來。
  5. 當我們的js里需要用到依賴所返回的結果時(通常是一個key value類型的object),requireJS便會把之前那個保存回調方法的數據結構里面的方法拿出來并且運行,然后把結果給需要依賴的方法。

以上就是一個簡單的流程。

?? SeaJS與RequireJS最大的區別

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!

注意我這里說的是執行(真正運行define中的代碼)模塊, 而非加載(load文件)模塊.模塊的加載都是并行的, 沒有區別, 區別在于執行模塊的時機, 或者說是解析.

AMD 的 CommonJS wrapping
個人覺得,AMD 的這個特性有好有壞:
首先,盡早執行依賴可以盡早發現錯誤。上面的代碼中,假如 a 模塊中拋異常,那么 main.js 在調用 factory 方法之前一定會收到錯誤,factory 不會執行;如果按需執行依賴,結果是:1)沒有進入使用 a 模塊的分支時,不會發生錯誤;2)出錯時,main.js 的 factory 方法很可能執行了一半。
另外,盡早執行依賴通常可以帶來更好的用戶體驗,也容易產生浪費。例如模塊 a 依賴了另外一個需要異步加載數據的模塊 b,盡早執行 b 可以讓等待時間更短,同時如果 b 最后沒被用到,帶寬和內存開銷就浪費了;這種場景下,按需執行依賴可以避免浪費,但是帶來更長的等待時間。
我個人更傾向于 AMD 這種做法。舉一個不太恰當的例子:Chrome 和 Firefox 為了更好的體驗,對于某些類型的文件,點擊下載地址后會詢問是否保存,這時候實際上已經開始了下載。有時候等了很久才點確認,會開心地發現文件已經下好;如果點取消,瀏覽器會取消下載,已下載的部分就浪費了。

shim

這是因為 main.js 中 mod1 和 mod2 兩個模塊并行加載,且加載完就執行,所以前兩行輸出順序取決于哪個 js 先加載完。如果一定要讓 mod2 在 mod1 之后執行,需要在 define 模塊時申明依賴,或者通過 require.config 配置依賴:
JSrequire.config({ shim: { 'mod2': { deps : ['mod1'] } }});

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容