【第22題】理解 JS 模塊化

題目描述

簡單描述一下你所瞭解的JS模塊化

答案解析

這道題目主要考察對JS模塊化發展歷程的瞭解,以及發展中出現的一些規範和技術的掌握。

模塊化是每一種語言膨脹的畢竟之路,JS 也不例外,從原來的不支持模塊化,到現在支持模塊化,經歷了一個曲折的過程。

JS 模塊化產生的原因

以前JS本身沒有模塊化的概念和相關API,開發者一般都是在html中引入多個script標籤,業務邏輯複雜時,就會帶來很多問題,比如:

  1. 全局作用域下容易造成變量衝突
  2. 文件只能按照 script的書寫順序進行加載
  3. 開發人員必須主觀解決模塊和代碼庫的依賴關係
  4. 在大型項目中各種資源難以管理,長期積累的問題導致代碼庫混亂不堪

模塊化的作用

它可以幫助開發者拆分和組織代碼,方便複用功能,降低項目開發的複雜度,提高可維護性。

模塊化方案及規範

一、閉包

在模塊化規範形成之前,JS 開發者通常利用閉包來解決全局作用域的污染問題,一般是通過自定義暴露行爲來區分私有成員和公有成員。

let myModule = (function (window) {
    let name = '前端名獅'  // private
    // public
    function setName(str) {
      name = str
    }
    // public
    function getName() {
      return name
    }
    return { setName, getName }  // 暴露行爲
})(window)

二、CommonJS

JS 一開始只能運行於瀏覽器中,所以一直被詬病。爲了突破JS的運行環境,CommonJS 規範出現了,它定義了一些規範和API(主要指非瀏覽器端的),使 JS 語言擁有了類似Python、Java等後端編程語言的能力。這樣的話,開發者可以使用CommonJS API編寫應用程序,然後這些應用可以運行在不同的JavaScript解釋器和不同的主機環境中。

2009年,美國程序員Ryan Dahl創造了node.js項目,將javascript語言用於服務器端編程。這標誌"Javascript模塊化編程"正式誕生。NodeJS是CommonJS規範的實現,webpack 也是以CommonJS的形式來書寫的。

node 模塊化示例:

// math.js 文件
let math = {
    add: function(a, b) {
        console.log(a + b);
    }
}

module.exports = math;

// app.js 文件
let math = require('./math.js');
math.add(1, 1);

三、AMD && CMD

基於commonJS規範的nodeJS出來以後,服務端的模塊概念已經形成,如果將其應用到瀏覽器端,會出現什麼問題呢?

let math = require('./math.js');
math.add(1, 1);

上面代碼執行require的時候,需要等math.js文件加載完成,才能繼續執行,如果加載時間過長,頁面就會出現“假死”狀態。

這對服務器端不是一個問題,因爲所有的模塊都存放在本地硬盤,可以同步加載完成,等待時間就是硬盤的讀取時間。但是,對於瀏覽器,這卻是一個大問題,因爲模塊都放在服務器端,文件的加載需要通過HTTP請求,等待時間取決於網速的快慢,可能要等很長時間。

CommonJS是主要爲了JS在後端的表現制定的,是不適合前端的 ,所以出現了AMD、CMD、UMD等等一系列可以在瀏覽器等終端實現的異步加載的模塊化方案**,我們最熟悉的require.js就是AMD的產物,seajs是CMD的產物。**

// AMD
require(['a', 'b'], function(math) {
 a.doSomething();  
 b.doSomething();
});

// CMD

define(function(require, exports, module) {  
    var a = require('./a')  
    a.doSomething();  
    ...
    var b = require('./b')   // 依賴可以就近書寫  
    b.doSomething();
})

AMD 推崇依賴前置,CMD 推崇依賴就近。

上面這句話的意思就是:CMD加載完某個依賴模塊後並不執行,只是下載而已,在所有依賴模塊加載完成後進入主邏輯,遇到require語句的時候才執行對應的模塊,這樣模塊的執行順序和書寫順序是完全一致的。

四、ES6 Module

ES6的模塊化已經不是規範了,而是JS語言的特性。隨着ES6的推出,AMD和CMD也隨之成爲了歷史。ES6模塊與模塊化規範相比,有兩大特點:

  1. 模塊化規範輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用。
  2. 模塊化規範是運行時加載,ES6 模塊是編譯時輸出接口。

模塊化規範輸出的是一個對象,該對象只有在腳本運行完纔會生成。而 ES6 模塊不是對象,ES6 module 是一個多對象輸出,多對象加載的模型。從原理上來說,模塊化規範是匿名函數自調用的封裝,而ES6 module則是用匿名函數自調用去調用輸出的成員。

注意:目前的瀏覽器幾乎都不支持 ES6 的模塊機制,所以我們要用 Babel 把 ES6 的模塊機制轉換成 CommonJS 的形式,然後使用 Browserify 或者 Webpack 這樣的打包工具把他們打包起來。達到模塊化加載效果類似於 seajs代碼

展望

1. Http 2.0 對 js 模塊化的推動

js 模塊化定義的再美好,瀏覽器端的支持粒度永遠是瓶頸,http 2.0 正是考慮到了這個因素,大力支持了 ES 2015 模塊化規範。

隨着 HTTP/2 流行起來,請求和響應可以並行,一次連接允許多個請求,對於前端來說,不再需要在開發和上線時再做編譯這個動作。

ES2015 Modules 也只是解決了開發的問題,由於瀏覽器的特殊性,還是要經過繁瑣打包的過程,等 Import,Export 和 HTTP 2.0 被主流瀏覽器支持,那時候纔是徹底的模塊化。

前端複雜度不斷提高,促使着模塊化的改進,代理(瀏覽器、node) 的支持程度,與前端特殊性(流量、緩存)可能前端永遠也離不開構建工具,新的標準會讓這些工作做的更好,同時取代、增強部分特徵,前端的未來是更加美好的,複雜度也更高。

2. html、css模塊化

文章中的 JS 的模塊化還不等於前端工程的模塊化,Web 界面是由 HTML、CSS 和 JS 三種語言實現,不論是 CommonJS 還是 AMD 包括之後的方案都無法解決 CSS 與 HTML 模塊化的問題。

html 與 css 模塊化問題正是以後的方向。一句話,模塊化仍在路上。

關注我

掃一掃 關注我的公衆號【前端名獅】,更多精彩內容陪伴你!
【前端名獅】

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