要实现模块化加载器,有几个重点
1、JS文件路径解析
2、下载JS文件
3、将定义的模块缓存
4、加载依赖
我看到的几个实例中下载文件都是使用document创建script标签,设置src的方式下载文件,这里 我使用jquery的ajax方法下载JS文件,因此文件路径的解析会有些不同。使用创建script标签的方式可以获取当前运行的JS的文件路径,但是对于jquery的ajax就不行了。焦点script的src属性是空的,因此路径解析时如果是相对路径要依据模块化加载器的文件路径解析。且define的id直接被路径替换了,相当于模块名强制就是文件名。为了稍微靠近 考虑从options中预先定义一个存储名字-路径转换关系的array。
define中,将文件的路径、依赖数组、function存储起来
在use中,根据路径或预先定义的转换关系中的名字 找到模块的依赖数组和function,加载模块的依赖属性到模块的function中,将模块的function作为参数按use方法中定义的依赖顺序传递给use方法的参数function中,执行use方法的参数functiong。比较绕口,用伪代码辅助描述下:
define(id,deps,fun);
根据id作为键,将deps和fun存储起来
use(deps,fun);
遍历deps,根据当前元素作为路径下载JS文件,在该js中调用了define方法,下载到的文件是字符串,使用new Function()方法转成function。执行function 相当于执行了define方法,执行时 将真正想要的function和依赖数组存储起来了。因此执行后 根据当前元素作为键就可以获取到目标模块的依赖数组和function,此时有两种选择:1、遍历依赖数组,下载,执行2、将选择1的步骤封装成一个function,暂不执行 相当于一个虚引用 就是后置执行,将依赖和function封装成一个function并作为参数传递给use方法的参数fun
这里用到了apply方法
var a = 1;
function log(num) {
alert(num);
}
log.apply(a);
上面的代码相当于将a作为参数传递给了log并执行,刚才说的的将依赖和function封装成一个function如下
var a = function() {
//......省略内容
};
var b = function(fun) {
//......省略内容
};
var wrap = function() {
b.apply(a);
};
假定function a是模块的依赖 function b是模块的function,那么function wrap就是对它们的封装
最后,为了尽可能避免卡JS引擎,导致浏览器假死,在use方法中使用setTimeout,将后续操作都重新插入到JS引擎执行队列的后面,尽可能的保证渲染任务先执行完