解釋 JavaScript 的模組載入

此篇文章最近更新時間為2013-05-16 22:31:43 目前共有2篇留言

關於作者 - JosephJ

任職於 Faria。喜好戶外運動、2008 年 5 月完成「跑步環島」。對於新技術跟程式碼有著強烈的偏執狂。

每次在做新人的教育訓練時、發現大家比較無法理解 JavaScript 載入模組的概念 (純瀏覽器端的,非 Node.js)。
模組是程式開發很重要的概念,每個程式語言一定都有載入模組的需求,例如:

  • PHP

    require_once LIB_ROOT . "sdk/raven-php/lib/Raven/Autoloader.php";

  • Java

    import android.app.Activity; import android.content.Context; import android.os.Message;

  • Node.js

    require("http") require("./lib/socket.io")

  • JavaScript in HTML

    <script src="jquery-1.7.2.js"></script> <script src="jquery.ui.core.js"></script> <script src="jquery.ui.widget.js"></script> <script src="jquery.ui.accordion.js"></script>

但是傳統 JavaScript 模組化的問題實在太多:不同頁面間共用問題、前後順序的問題、Request 過多的效能問題、全域變數氾濫問題...
目前 HTML 本身還沒有一個通用的好解法,因此我們通常會使用內建模組實作的 YUI LibraryRequireJS 來處理

定義模組

其他的程式語言,像 PHP,大多不需要「定義」,就只是把別的 script 拉進來。
但瀏覽器中的 JavaScript 是很特別的,因為他跟 Server-side 語言不同,得先「下載完」並「等到相依模組已經下載完成」 才能執行。
所以要先定義,把要執行的東西放到 Callback,讓 Loader 去判斷什麼時候可以執行 Callback。

// YUI 定義模組:a.js + b.js
YUI.add('a', function (Y) {
    Y.a = 'a';
}, '0.0.1, {
    requires: {'b', 'c', 'd'}
});
YUI.add('b', function (Y) {
    Y.b = 'b';
}, '0.0.1, {
    requires: {'d', 'e', 'f'}
});

// RequireJS 定義模組:a.js + b.js
define('a', ['b', 'c', 'd'], function (b, c, d) {
    return 'a';
})
define('b', ['d', 'e', 'f'], function (d, e, f) {
    return 'b';
})

雖然做的事情一樣,但比較起來,RequireJS 的定義真的是容易理解許多。YUI 畢竟比較早誕生,語意離潮流比較遠一點 :p

啟用模組

假設你把上面的 a.js 與 b.js 直接用 script src 放到頁面上,是不會有任何作用的。
因為 JavaScript 還需要一個「啟用」的動作。

// YUI 啟用模組 init.js
YUI().use('a', 'b' function (Y) {
    alert(Y.a); // 'a'
    alert(Y.b); // 'b'
});

// RequireJS 啟用模組 init.js
require(['a', 'b'] function (a, b) {
    alert(a); // 'a'
    alert(b); // 'b'
});
  1. 它首先會去下載 a.js 與 b.js,
  2. 下載並載入 a.js 發現它還缺少 b.js + c.js + d.js (b.js 可能已經好了)
  3. 下載並載入 b.js 發現它還缺少 d.js + e.js + f.js (d.js 可能已經好了)
  4. YUI 或 RequireJS 會記錄哪些還沒下載回來,也就是 c.js + d.js + e.js + f.js
  5. 當 b, c, d 都在頁面 ready 後,定義 a 模組的 callback 會被立刻執行
  6. 當 d, e, f 都在頁面 ready 後,定義 b 模組的 callback 會被立刻執行
  7. 當 a, b 都 ready 後,啟用模組的 callback 就會被執行

註:最後三步在 YUI 與 RequireJS 的處理應該不太一樣。上面的流程比較偏 YUI 的,因為他只是在 YUI Instance 的物件上掛子物件,可以立刻執行。而 RequireJS 因為是用 return 的方式,應該是啟用的 callback 執行後才會去執行相依模組的 callback。

結語

辛苦 JavaScript 的新鮮人,模組化的載入流程的確比其他語言來得複雜許多。
這也得歸咎於世界上最複雜的開發環境 - 瀏覽器。



Comments

  1. 大王 2017-09-14 22:55:42
    非常有用的文章~ 謝謝您

    https://zh.dictpedia.org
  2. 老吳 2013-12-05 09:09:20
    請問版主,
    對於模組開發我有些問題,CSS 該如何模組化?若有些模組(partialview),又該如何動態載入?
暱稱: 必填。
Email: 非必填。若填寫為不公開欄位,僅供站長參考聯繫。
內容: 必填。限 255 個字元以內。
驗證碼:
送出

Facebook Comment