最近寫一個小遊戲的時候用的是RequireJs
構建項目,順便補了一下RequireJs
,下面講解一些基礎和進階的用法。html
AMDAsync Module Definition
表明的意思爲異步模塊定義,是Javascript
模塊化的瀏覽器解決方案,它採用異步的方式加載模塊,模塊的加載不影響它後面語句的運行。全部依賴這個模塊的語句,都定義在回調函數中,等到加載完成以後,這個回調函數纔會運行。jquery
AMD規範定義了一個函數define
,經過define
方法定義模塊:git
define(id?, dependencies?, factory);
而且採用require()
語句加載模塊:github
require([module], callback);
引入的模塊和回調函數不是同步的,因此瀏覽器不會由於引入的模塊加載不成功而假死。api
RequireJS
是一個基於AMD
規範實現的JavaScript
文件和模塊加載器。它針對瀏覽器內使用進行了優化,而且對其餘JS
環境(Rhino和Node)
作了兼容。使用RequireJS
這樣的模塊化腳本加載器能夠提升代碼的速度和質量。瀏覽器
根據官方文檔和項目實例,接下來講一下ReuqireJS
的基本使用:app
下載最新版的RequireJS。異步
下面是官方示例的RequireJS
項目結構,對內容作了小小的改動,www
做爲項目的根目錄,lib
中存放項目依賴即須要的一些JS
庫,app.js
爲主入口文件,app
中存放本身寫的模塊文件。模塊化
1. index.html函數
index.html
中定義了一個script
標籤來引入require.js
,其中data-main
屬性是一個自定義屬性,這個屬性指定在加載完 reuqire.js
後,就將屬性指定路徑下的JS
文件並運行,這個文件即入口文件,這裏的app.js
的js
後綴被省略掉了。
<!DOCTYPE html> <html> <head> <script data-main="app" src="lib/require.js"></script> </head> <body> <h1>Hello World</h1> </body> </html>
若是
<script/>
~~~~ 標籤引入
require.js 時沒有指定
data-main 屬性,則以引入該
js 的
html 文件所在的路徑爲根路徑,若是有指定
data-main 屬性,也就是有指定入口文件,則以入口文件所在的路徑爲根路徑。
2. app.js
Main.js
加載主模塊而且配置項目依賴,要改變 RequireJS
的默認配置,可使用require.config
函數傳入一個可選參數對象。下面是一些可使用的配置:
// For any third party dependencies, like jQuery, place them in the lib folder. // Configure loading modules from the lib directory, // except for 'app' ones, which are in a sibling // directory. requirejs.config({ // 模塊加載的根路徑。 baseUrl: ".", // 用於一些經常使用庫文件或者文件夾路徑映射,js後綴能夠省略 paths: { app: "app/", fmt: "lib/fmt", }, }); // Start loading the main app file. Put all of // your application logic in there. requirejs(["app/main"]);
若是在
require.config() 中有配置
baseUrl,則以
baseUrl 的路徑爲根路徑,這條規則會覆蓋上面
data-main
的效果。
3. app/
Main.js
中咱們經過require
函數加載了一個message
模塊,該模塊用於打印一些定義好的字符串。
define(function (require) { var msg = require("./message"); msg.helloWorld(); });
Main.js
中使用的模塊定義在message.js
中,他引入了一個輸出依賴fmt
。
define(["fmt"], function (fmt) { return { helloWorld: function () { fmt.println("hello word"); }, }; });
這兩種依賴的加載方式又和不一樣稍後介紹。
4. lib/
Lib/fmt.js
中我定義一個 js
模塊模擬go
的fmt
包,經過return
對外暴露出接口。注意,暴露的對象就是引入的對象。
define(function () { var print = function (msg) { console.log(msg); }; var println = function (msg) { console.log(msg + "\n"); }; return { moduleName: "fmt", print: print, println: println, }; });
要改變RequireJS
的默認配置,可使用require.config
函數傳入一個可選參數對象,其實這個對象能夠配置五個屬性:
require.config({ baseUrl: '.', paths: { app: "app/", fmt: "lib/fmt", }, shim: { 'backbone': { deps: ['underscore', 'jquery'], exports: 'Backbone' }, 'underscore': { exports: '_' } }, config: { 'app/main': { ENV: 'development' } }, map: { 'script/newmodule': { 'foo': 'foo1.2' }, 'script/oldmodule': { 'foo': 'foo1.0' } }, });
1. baseUrl
baseUrl
做爲加載模塊的根路徑。在配置這個屬性後,以後全部的路徑定義都是基於這個根路徑的(包括配置和依賴引入中)。
2. path
用於一些經常使用庫文件或者文件夾路徑映射,定義以後能夠直接在依賴引入中使用。
3. shim
雖然目前已經有一部分流行的函數庫符合 AMD 規範,但還有不少庫並不符合。shim
就是爲了加載這些非AMD
規範的js
,並解決其載入順序的,好比上面的backbone
。
4. config
config
將配置信息傳給一個模塊。這些配置每每是application
級別的信息,須要一個手段將它們向下傳遞給模塊。
config: { 'app/main': { ENV: 'development' } }
能夠經過加載特殊的依賴module
來獲取這些信息。
define(['module'], function (module) { var ENV = module.config().ENV; // development var msg = require("./message"); msg.helloWorld(); });
5. map
對於給定的模塊前綴,使用一個不一樣的模塊 ID 來加載該模塊。該手段對於某些大型項目很重要。好比上面配置之後,不一樣的模塊會使用不一樣版本的foo
。
當some/newmodule
調用了require('foo')
,它將獲取到foo1.2.js
文件,當oldmodule
調用 require('foo')
,時它將獲取到 foo1.0.js
文件。
map
還支持*
,意思是「對於全部的模塊加載,使用本 map
配置」。若是還有更細化的 map
配置,會優先於*
配置。
requirejs.config({ map: { '*': { 'foo': 'foo1.2' }, 'some/oldmodule': { 'foo': 'foo1.0' } } });
1. 對象
若是一個模塊僅含鍵值對,沒有任何依賴,能夠直接在define
中定義。
define({ foo: "foo", bar: function(){} });
2. 須要預處理的對象
define(function () { console.log("Do something..."); return { foo: "foo", bar: function(){} } });
3. 只有一個函數
沒有任何依賴的函數直接這麼定義:
define(function () { return function (){}; });
調用時直接打()
調用:
require(['lib/foo'],function (foo) { foo(); });
4. 須要其餘的依賴:
define(['jquery'],function($){ return function (){}; });
假設咱們有以下 a、b
兩個互相依賴的模塊,咱們若是調用 b
模塊的 b
方法。
// app/a.js define(['app/b'],function(b){ return function() { b() } }); // app/b.js define(['app/a'],function(a){ return function() { a() } });
會發現 b
調用 a
正常,可是 a
中調用 b
方法會報 undefined
錯誤。
require(['app/b'],function (b) { b(); // b is not defined. });
解決:
循環依賴比較罕見,對於循環依賴,只要依賴環中任何一條邊是運行時依賴,這個環理論上就是活的。而若是所有邊都是裝載時依賴,這個環就是死的。
對模塊 a
進行以下修改,即再也不依賴前置加載。而是經過引入 require
依賴,而後再經過 require()
方法去載入模塊 b
,並在回調中去執行。
// app/a.js define(['require'],function(require){ var b = require('b') return function() { b() } });