在javascript是沒有類似java或其他語言的模組概念的,因此也不可能通過import或using等關鍵字來引用模組,這樣造成了複雜專案中前端程式碼混亂,變數互相影響等。
因此在複雜專案中引入AMD的概念,AMD:全稱是Asynchronous Module Definition,即非同步模組載入機制。通過AMD可以不需要在頁面中手動新增<script>來引用指令碼,而通過定義依賴自動載入模組指令碼,接下來的程式碼將講解如何實現建議的AMD模組,如果需要檢視比較詳細的實現可以下載requirejs原始碼。
簡易實現整體思路:
1.將模組名及模組檔案地址存入記憶體
2.通過define方法將模組名及模組依賴關係以及模組實現程式碼存入記憶體
3.require方法通過loadscript方法將需要依賴的模組程式碼匯入並執行define方法存入記憶體,模組通過入參傳入實際程式碼中,從而完成模組載入。
1.定義模組:
實現模組的定義,並將模組定義儲存。
/** * * @param id 模組名 * @param deps 依賴模組 * @param factory 模組實現 */ define: function (id, deps, factory) {
在定義模組中,需要將模組名,模組依賴,模組程式碼儲存至記憶體中
/** * * @param id 模組名 * @param deps 依賴模組 * @param factory 模組實現 */ define: function (id, deps, factory) { // 模組是否存在 if (modules[id]) throw new Error("module:" + id + "已經存在!"); if (arguments.length > 2) { modules[id] = { id: id, deps: deps, factory: factory } } else if (arguments.length == 2) { modules[id] = { id: id, factory: deps } } else { throw new Error("module:引數有誤!"); } },
2.引用模組:
輸入依賴模組名,執行程式碼,程式碼示例如下:
/** * 非同步匯入模組 * @param deps 依賴模組 * @param callback * @returns {{}} */ require: function (deps, callback) { // 插入指令碼 deps = [].slice.call(deps); // 獲取依賴指令碼 loadScript(deps, buildModule, callback); },
詳細步驟:
首先需要從依賴的資料夾中匯入指令碼,
/** * 從外部載入js * @param deps 依賴模組 * @param buildModule 建立模組方法 * @param callback */ function loadScript(deps, buildModule, callback) { var depJsCounter = 0; deps.forEach(function (dep) { var script = document.createElement("script") script.type = "text/javascript"; script.src = configs[dep]; document.getElementsByTagName("head")[0].appendChild(script); script.onload = function () { // 依賴js載入計數標記 depJsCounter++; if (depJsCounter == deps.length) { buildModule(deps, callback)(); } }; }); }
構建模組,從全域性module中取出依賴模組,將依賴模組作為入參注入到現有模組,最後執行現有模組
/** * 建立模組 * @param deps 依賴模組 * @param callback * @returns {Function} */ var buildModule = function (deps, callback) { return function () { // 獲取依賴模組 var args = []; deps = [].slice.call(deps); deps.forEach(function (dep) { var module = modules[dep] if (typeof module.factory === 'function') module.factory = module.factory(); args.push(module.factory) }) // 將依賴模組注入到callback中 var temp = {}; callback.apply(temp, args); return temp } }
3.註冊模組
註冊模組主要將名字與檔案路徑關聯起來,便於從路徑中下載js,程式碼清單如下:
/** * 註冊模組 * @param obj */ config: function (obj) { var path = obj.paths; for (var el in path) { Object.defineProperty(configs, el, { enumerable: false, configurable: false, writable: true, value: path[el] }) } } }
4.執行例項
編寫模組
define('module1', function () { var module1 = {}; module1.sayhello = function () { return 'hello module1'; } return module1; });
將程式碼儲存js檔案並取名module1
新建html檔案,在html中先註冊模組,通過require 匯入模組,並利用模組編寫程式碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <script src="/demo/01Requirejs/require.js"></script> </head> <body> </body> </html> <script> require.config({ paths:{ module1:'/demo/01Requirejs/module1.js' } }); require(['module1'],function(module1){ alert(module1.sayhello()); }) </script>