RequireJS模塊化加載


 

引子

RequireJS模塊化加載

本文主要是介紹RequireJS模塊化加載,引進RequireJS,並不對其做深入研討,因為我本身對RequireJS了解的不是很深入。引入RequireJS模塊化加載,為后續繼續學習打下基礎。

RequireJS 簡介

RequireJS 是一個非常小巧的 JavaScript 模塊載入框架,是 AMD 規范最好的實現者之一。最新版本的 RequireJS 壓縮后只有 14K,堪稱非常輕量。它還同時可以和其他的框架協同工作,使用 RequireJS 必將使您的前端代碼質量得以提升。 目前最新版本的 RequireJS 1.0.8 在 IE 6+、Firefox 2+、Safari 3.2+、Chrome 3+、Opera 10+ 上都工作的很好。

使用 RequireJS 加載 JavaScript 文件

即使您的 Web 前端由於種種歷史原因還沒有打算進行模塊化的設計,RequireJS 作為 JavaScript 文件的加載器,還是可以幫助您來完成異步非阻塞的文件加載。

如案例一 所示,有兩個 JavaScript 文件 a.js 和 b.js,里面各自定義了 myFunctionA 和 myFunctionB 兩個方法,通過下面這個方式可以用 RequireJS 來加載這兩個文件,在 function 部分的代碼可以引用這兩個文件里的方法。

案例一: 加載 JavaScript 文件

 <script src="./js/require.js"></script> <script> require(["./js/a.js", "./js/b.js"], function() { myFunctionA(); myFunctionB(); }); </script>

require 方法里的這個字符串數組參數可以允許不同的值,當字符串是以”.js”結尾,或者以”/”開頭,或者就是一個 URL 時,RequireJS 會認為用戶是在直接加載一個 JavaScript 文件,否則,當字符串是類似”my/module”的時候,它會認為這是一個模塊,並且會以用戶配置的 baseUrl 和 paths 來加載相應的模塊所在的 JavaScript 文件。配置的部分會在稍后詳細介紹。

這里要指出的是,RequireJS 默認情況下並沒有保證 myFunctionA 和 myFunctionB 一定是在頁面加載完成以后執行的,在有需要保證頁面加載以后執行腳本時,RequireJS 提供了一個獨立的 domReady 模塊,需要去 RequireJS 官方網站下載這個模塊,它並沒有包含在 RequireJS 中。有了 domReady 模塊,案例一 的代碼稍做修改加上對 domReady 的依賴就可以了。

案例二: 頁面加載后執行 JavaScript

 <script src="./js/require.js"></script> 
     <script> 
    require(["domReady!", "./js/a.js", "./js/b.js"], function() { 
             myFunctionA(); 
             myFunctionB(); 
        }); 
     </script>

 

執行案例二的代碼后,通過 Firebug 可以看到 RequireJS 會在當前的頁面上插入為 a.js 和 b.js 分別聲明了一個 < script> 標簽,用於異步方式下載 JavaScript 文件。async 屬性目前絕大部分瀏覽器已經支持,它表明了這個 < script> 標簽中的 js 文件不會阻塞其他頁面內容的下載。

案例三:RequireJS 插入的 < script>

 <script type="text/javascript" charset="utf-8" async="" data-requirecontext="_" 
 data-requiremodule="js/a.js" src="js/a.js"></script>

 

使用 RequireJS 來定義 JavaScript 模塊

這里的 JavaScript 模塊與傳統的 JavaScript 代碼不一樣的地方在於它無須訪問全局的變量。模塊化的設計使得 JavaScript 代碼在需要訪問”全局變量”的時候,都可以通過依賴關系,把這些”全局變量”作為參數傳遞到模塊的實現體里,在實現中就避免了訪問或者聲明全局的變量或者函數,有效的避免大量而且復雜的命名空間管理。

如同 CommonJS 的 AMD 規范所述,定義 JavaScript 模塊是通過 define 方法來實現的。

下面我們先來看一個簡單的例子,這個例子通過定義一個 student 模塊和一個 class 模塊,在主程序中實現創建 student 對象並將 student 對象放到 class 中去。

案例四: student 模塊,student.js

 define(function(){ 
     return { 
        createStudent: function(name, gender){ 
             return { 
                 name: name, 
                 gender: gender 
             }; 
        } 
     }; 
 });

 

案例五:class 模塊,class.js

 define(function() { 
 var allStudents = []; 
        return { 
            classID: "001", 
            department: "computer", 
            addToClass: function(student) { 
            allStudents.push(student); 
            }, 
            getClassSize: function() { 
            return allStudents.length; 
            } 
        }; 
     } 
 );

 

案例六: 主程序

 require(["js/student", "js/class"], function(student, clz) { 
 clz.addToClass(student.createStudent("Jack", "male")); 
 clz.addToClass(student.createStudent("Rose", "female")); 
 console.log(clz.getClassSize());  // 輸出 2 
 });

 

student 模塊和 class 模塊都是獨立的模塊,下面我們再定義一個新的模塊,這個模塊依賴 student 和 class 模塊,這樣主程序部分的邏輯也可以包裝進去了。

案例七: 依賴 student 和 class 模塊的 manager 模塊,manager.js

 define(["js/student", "js/class"], function(student, clz){ 
 return { 
    addNewStudent: function(name, gender){ 
    clz.addToClass(student.createStudent(name, gender)); 
        }, 
    getMyClassSize: function(){ 
    return clz.getClassSize(); 
    } 
     }; 
 });

 

案例八:新的主程序

 require(["js/manager"], function(manager) { 
 manager.addNewStudent("Jack", "male"); 
 manager.addNewStudent("Rose", "female"); 
 console.log(manager.getMyClassSize());// 輸出 2 
 });

 

通過上面的代碼示例,我們已經清楚的了解了如何寫一個模塊,這個模塊如何被使用,模塊間的依賴關系如何定義。還是有一些使用技巧需要提示一下:

盡量不要提供模塊的 ID,如 AMD 規范所述,這個 ID 是可選項,如果提供了,在 RequireJS 的實現中會影響模塊的可遷移性,文件位置變化會導致需要手動修改該 ID。

每個 JavaScript 文件只定義一個模塊,模塊名稱和文件路徑的查找算法決定了這種方式是最優的,多個的模塊和文件會被優化器進行優化。 避免模塊的循環依賴,如果實在避免不了,可以模塊中加上對”require”模塊的依賴,在代碼中直接用

require(”dependencyModuleName”)

 

配置 RequireJS

前面的介紹中,我們似乎忽略了一個基本問題,模塊名字是怎么來的?當我在 require 一個模塊時,這個模塊是如何映射到具體的 JavaScript 文件上去?這就涉及到如何配置 RequireJS。

最簡化的加載 RequireJS 的方式如案例2 所示,在這種情況下,我們沒有指定一個 baseUrl 和 paths 給 RequireJS,如果通過如案例10 所示方式,則 data-main 指定了一個在當前 index.html 目錄並行的文件夾下的 /js/main.js 作為程序入口,而 /js 目錄也將作為 baseUrl 在其他模塊定義時候使用。

案例九:載入 require.js

 <script data-main="js/main" src="scripts/require.js"></script>

 

因此,我們前面示例中的所有模塊依賴,都可以去掉”js/”,直接寫 ”student”, ”class”,”manager” 等。 一種更為直接的方式顯示指定 baseUrl 和 paths 就是利用 require.config 來設置這些參數。如案例十 所示。

案例十. 配置 RequireJS

 <script type="text/javascript" src="./js/require.js"></script> 
 <script type="text/javascript"> 
  require.config({ 
    baseUrl: "./js", 
    paths: { 
        "some": "some/v1"
    }, 
 waitSeconds: 10 
 }); 
  require( ["some/module", "my/module", "./js/a.js"], 
    function(someModule,    myModule) {} 
  ); 
 </script>

 

baseUrl指明的是所有模塊的 base URL,比如”my/module”所加載的 script實際上就是 /js/my/module.js。注意,以 .js 結尾的文件加載時不會使用該 baseUrl,它們仍然會使用當前 index.html所在的相對路徑來加載,所以仍然要加上”./js/”。如果 baseUrl沒有指定,那么就會使用 data-main中指定的路徑。

paths 中定義的路徑是用於替換模塊中的路徑,如上例中的 some/module 具體的 JavaScript 文件路徑是 /js/some/v1/module.js 。 waitSeconds 是指定最多花多長等待時間來加載一個 JavaScript 文件,用戶不指定的情況下默認為 7 秒。

另外一個重要的配置是 packages,它可以指定其他符合 CommonJS AMD 規范的目錄結構,由此帶來了豐富的擴展性。如 Dojo、jQuery 等的模塊也可以通過該配置來讓 RequireJS 加載。

其他可配置的選項還包括 locale、context、deps、callback等,有興趣的讀者可以在 RequireJS 的官方網站查閱相關文檔。

綜合運用 RequireJS

當 RequireJS 與其他框架一起工作的時候,顯然它是可以作為統一的加載器來加載其他框架。鑒於 jQuery、Dojo 等已經支持了 AMD ,那么就有可能在定義自己的模塊的時候,通過適當配置,直接把其他框架的模塊作為依賴對象。

RequireJS 和 Dojo

案例十是一個基本的 RequireJS 和 Dojo 集成配置方法,這里關鍵是將 dojo 和 dijit 都在 packages 里面注冊一下。

案例十一:配置 RequireJS 和 Dojo

 <script> 
 require = { 
 packages: [ 
 { 
 name: “dojo”, 
 location: “dojo”, 
 main:”lib/main-browser”, 
 lib: “.”
 }, 
 { 
 name: “dijit”, 
 location: “dijit”, 
 main:”lib/main”, 
 lib: “.”
 } 
 ], 
 paths: { 
 require: “./js”
 }, 
 ready: function () { 
 require([“my/module”], function (module) { 
 }); 
 } 
 }; 
 </script>

 

在定義 module 這個模塊時就可以直接將 dojo 和 dijit 里的模塊作為依賴對象了。

RequireJS 和 jQuery

把 jQuery 作為一個依賴模塊來使用也非常簡單,只需要在 RequireJS 里的 config 里做相應的配置就可以了。

案例十二:配置 RequireJS 和 jQuery

 require.config({ 
 paths: { 
"jquery": "./js/jquery-1.7"
 } 
 }); 
 require(["jquery"],function(jQ){ 
 console.log(jQ); 
 });

 

RequireJS 和 Web Workers

Web Workers 是多線程的 JavaScript,每個 worker 里面的腳本都 會啟動一個新的線程來執行,通過在 worker 里面用 importsScript 來加載 require.js 可以直接在 worker 里面使用 RequireJS 。

案例十三: RequireJS 和 Web Workers

 importScripts('./js/require.js'); 
 require(["require"], 
    function(require) { 
        postMessage("test"); 
    } 
 );

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM