一步步实现Amd-loader(三)

通过前面几步,我们基本实现了一个模块化编程,现在要为程序实现AMD的接口(define方法)
AMD的规范只定义了一个函数 “define”,它是全局变量。函数的描述为:

define(id?, dependencies?, factory);

具体请参考 –> Amd规范

实现AMD的类库两个比较著名的分别是RequireJSCurlJS
说实话如果直接看这两个类库的源码,可能多少有点难,甚至懵逼,建议初学者可以参考别的实现:foio.github.io

我们把每一个模块改为一个js文件,然后实现我们的AMD模块加载器

add.js

1
2
3
4
5
define([],function () {
return function () {
console.log("define an add module ....");
}
});

minus.js

1
2
3
4
5
define([],function () {
return function () {
console.log("define minus module ....");
}
});

calc.js

1
2
3
4
5
6
define(['./add','./minus'],function (add,minus) {
return {
add: add,
minus: minus
}
});

main.js

1
2
3
4
5
6
7
8
9
10
require(['./calc'],function (calc) {
var btnAddEl = document.getElementById('btnAdd');
var btnMinusEl = document.getElementById('btnMinus');
btnAddEl.addEventListener("click",function () {
calc.add();
});
btnMinusEl.addEventListener("click",function () {
calc.minus();
});
});

通过分析,可以整个过程看做是一个”栈”操作.

  • 1.define() 操作定义一个Module,立即压入”栈”(这里push到数组中);
  • 2.加载该模块的deps(依赖数组)
  • 3.出”栈”执行模块的工厂函数,获取返回值

define 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
function define(id,deps,length){
var len = arguments.length;
if (len == 2) {
factory = deps;
deps = id;
id = undefined;
}
var mod = new Module(id,deps,factory);
context.newModules.push(mod);
context.waitingModules.push(mod);
mod.loadDeps();
exec();
}

exec函数(执行context.waitingModules中的模块,如果已经准备好,则从数组中剔除)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* 执行所有等待模块,如果模块加载完成,则从等待数组剔除
* @return {[type]} [description]
*/
function exec() {
var i;
var j = 0;
var depID;
var len = context.waitingModules.length;
var val;
var mod;
var args;
var callback;
for(i = len;i--;){
mod = context.waitingModules[i];
if ((!mod.returnVal) && mod.checkDeps()) {//如果一个没有执行输出结果,并且依赖已经准备好
//从等待数组中删除
context.waitingModules.splice(i,1);
args = [];
callback = mod.factory;
for(j = mod.deps.length;j--;){
depID = mod.deps[j];
args.unshift(mod.getDepsValue(depID));
}
val = callback.apply(global,args);
mod.returnVal = val;
}
}
}

require函数其实也是一个define函数的过程,为了便于理解,暂时不处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 定义require函数
* @param {[type]} deps [description]
* @param {Function} callback [description]
* @return {[type]} [description]
*/
function require(deps, callback) {
var mod = new Module(context.topModule,deps,callback);
context.loads[context.topModule] = true;
context.modulesMap[context.topModule] = mod; //top main module already loaded
context.newModules.push(mod);
context.waitingModules.push(mod);
mod.loadDeps();
exec();
}

具体实现可以参考我的github或者foio.github.io实现.