require.js及模塊化編程相關概念

github地址:

https://github.com/requirejs/requirejs

好的文章:https://www.jianshu.com/p/8687f539642c

require.js 是一個JavaScript文件和模塊加載器,也是模塊管理工具

requireJs 作用是什麼,優勢是什麼? 它解決什麼難題?

1. 有效防止了命名衝突

2. 聲明瞭不同 JS 文件之間的依賴關係

3. JS代碼以模塊化的 方式組織。

requireJs 爲解決前端代碼庫的組織難題,它的解決方案是:

模塊化組織js文件

異步加載js文件

JavaScript模塊化編程

JavaScript模塊化編程的目的是爲了讓開發者 僅需實現核心的業務邏輯,其他的都加載別人寫好的模塊就行。

但是JavaScript並不是模塊化的語言,ES6才正式支持類和模塊,之前的版本不支持類,更不用說module.

什麼是模塊?  

模塊的原始寫法:

將不同函數及變量簡單的放在一起,看作一個模塊。

var a = xxx;

function func1(){...}

function func2(){...}

缺點是:污染全局變量,無法保證 不與其他模塊發生命名衝突。而且不能清晰的看出模塊成員之間關係;

模塊的對象寫法

將模塊定義爲一個對象,所有模塊成員放在對象裏邊。

//將屬性和操作都封裝在對象中

var module = new Object({

_prop:11,

func1:function(){...}

func2:function(){...}

})

//使用時直接調用對象的屬性;

module.func1();

確定:暴露了模塊成員,內部狀態 可以被外部改寫。

module._prop = 100;

立即執行函數寫法:

IIFE( Immediately-Invoked Function Express) 可以達到不暴露私有成員的目的

var module = (function(){
  var _prop = 0;
  var fn1 = function(){...};
  var fn2 = function(){...};
  return {fn1:fn1, fn2:fn2};
})();

放大模式/ 繼承模式 (augmentation).

如果一個模塊很大,必須被分成幾個部分,或者一個模塊需要繼承另外一個模塊。

var module = (function(mod){
  mod.fn = function(){...};
  return mod;
})(module);

寬放大模式(Loose Augmentation): 放大模式的改進

瀏覽器環境中 各個模塊 通常都是通過網絡獲取的。採用放大模式,第一個執行的部分 可能使用一個不存在的空對象,

此時需要要使用寬放大模式 

var module = (function(mod){
  mod.fn = function(){...};
  return mod;
})(window.module || {});

如何保證模塊的獨立性?如何使用全局變量(其他模塊)?

獨立性是模塊的重要特點,模塊內部最好不要與程序的其他模塊直接交互。爲了在模塊內部使用全局變量,

必須顯示地將其他變量 作爲參數輸入模塊

var module = (function($){
  
})(jQuery);

AMD規範

Js目前沒有官方規範,通用的JS 模塊規範有2種,CommonJS和AMD

CommonJS

老實說在瀏覽器環境下,沒有模塊並不是特別大的問題,畢竟網頁的複雜性有限。但是對於服務端編程,

一定要有模塊,否則無法編程。

2009年,美國程序員Ryan Dahl創建了NodeJS項目,將JS用於服務端編程。由此標誌着JS模塊化編程的正式誕生。

NodeJS的模塊系統是參照CommonJS規範實現的,在CommonJS中有一個全局方法require(),用於加載模塊。

var match = require("math");

match.add(1,2)

由於一個重大的侷限,使得CommonJS規範不適用於瀏覽器環境。問題是對於服務器而言模塊都放在本地,可同步加載等待時間只是硬盤讀取時間。但是當瀏覽器中使用服務端的模塊時,等待時間取決於網速快慢,長時間的等待會造成瀏覽器處於“假死”狀態。

因此瀏覽器端的 模塊 不能使用“同步加載(synchronous)", 只能採用“異步加載(asynchronous)"方式,

這就是AMD規範誕生的背景。

AMD (Asynchronous Module Definition) 異步模塊加載。

所有依賴模塊的語句都定義在一個回調函數中,等到加載完成後,回調函數纔會執行。

AMD也採用了require()語句加載模塊,不同於CommonJS的是,它要求兩個參數。

// module參數爲一個數組,裏面的成員是要加載的模塊
// callback參數是模塊加載成功後執行的回調函數
require([module], callback)

// math模塊與math.add()加載不是同步的,瀏覽器不會發生假死,因此AMD比較適合瀏覽器環境。
require(["math"], function(math){
  math.add(1, 2);
});

RequireJS

加載資源文件

<script src="https://cdn.bootcss.com/require.js/2.3.5/require.js"></script>

在引入require.js文件之後,整個windows 對象就有 require()方法。可以通過require()方法來加載其他JS文件。

RequireJS的入口是 引入時指定的data-main屬性,在require.js引入後,會自動執行指向data-main屬性所指定的入口文件。

由於引入requireJS本身可能會造成頁面失去響應,解決的方式可將其放在網頁底部加載。或使用延遲加載。

<script src="./assets/scripts/require-2.3.5.js" data-main="js/main" async="true" defer></script>

主模塊:

data-main加載的是主模塊

baseUrl 可通過 requirejs.config手動設置,若沒有顯示指定config及data-main,則默認的baseUrl爲包含requireJS的

那個html頁面所屬的目錄。

$ vim js/main.js
/**
 * RequireJS全局配置文件
 */
requirejs.config({
    //設置項目路徑,項目會以baseUrl作爲相對路徑去查找模塊文件
    baseUrl:"./js",
    //預加載JS文件的配置項,默認可不用添加.js後綴
    paths:{
        //RequireJS默認假定所有的依賴資源都是JS腳本,因此無需再module ID上再加上js後綴。
        jquery:"../scripts/jquery-3.3.1"
    }
});

正常情況下,主模塊是依賴其他模塊的,此時要使用AMD規範定義的require()函數。

require([module], function(module){...});

/**
 * RequireJS全局配置文件
 */
require.config({
    //設置項目路徑,項目會以baseUrl作爲相對路徑去查找模塊文件
    baseUrl:"./js",
    //預加載JS文件的配置項,默認可不用添加.js後綴
    paths:{
        //RequireJS默認假定所有的依賴資源都是JS腳本,因此無需再module ID上再加上js後綴。
        jquery:"https://cdn.bootcss.com/jquery/3.3.1/jquery",
        bootstrap:"https://cdn.bootcss.com/bootstrap/4.1.1/js/bootstrap"
    }
});

require(['jquery', 'bootstrap'],function($, undefined){

});

RequireJS要求每個模塊是一個單獨的JS文件,如果多加載幾個模塊會發出多次HTTP請求,

實際上,雖然部分的函數庫符合AMD規範,但更多的庫並不符合。

RequireJS 如何加載非規範的模塊呢?

在使用require()之前,需在require.config()函數中定義非規範模塊的特徵。

require.config()接收一個配置對象,此對象除了paths屬性之外,還有一個shim屬性,專門用來配置不兼容的模塊。每個模塊需要定義exports值即輸出的變量名,表明這個模塊外部調用名稱。其次deps數組屬性表明該模塊的依賴性。

RequireJS源碼解析

requireJS工作流程

  • 載入模塊
  • 通過模塊名解析出模塊信息並計算出URL
  • 通過創建script的形式將模塊加載到頁面
  • 判斷被加載腳本若存在依賴則加載,若不存在則直接執行factory()
  • 等待所有腳本都加載完畢後執行回調函數

 

 

 

 

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