前段时间我开始基于SeaJS开发2.0版本的JRaiser,主要目的就是把这个库模块化。结合实际开发过程中遇到的问题,我重新写了一个更符合自身需求的JRaiser Loader以代替SeaJS(另一方面也是为了亲手写一个Loader)。与SeaJS一样,JRaiser Loader也是Wrappings规范(关于AMD与Wrappings的区别,这篇文章有详细说明)的实现,主要接口也与SeaJS保持一致(但功能暂时比SeaJS少)。下面以JRaiser Loader的实现为例介绍一下Loader的实现原理。
先介绍几个术语:
- 模块:模块化开发中的一个功能单元。它有一个唯一的Id作为标识,并可以依赖于其他模块。
- 任务:全局require函数的回调函数。在JRaiser Loader的内部处理中,任务也是模块。
- 就绪:当某个模块已经加载完成,并且不依赖于任何模块或者它依赖的所有模块已经就绪,这个模块就是就绪状态。
在模块化开发中,一个模块可以依赖于任意个模块,而被它依赖的模块又可以依赖于任意个其他模块。这就要求加载模块时必须一层一层把所有依赖的模块都加载进来,类似于树的遍历。由于前端动态加载JS的过程是异步的,也就是说,这是异步的遍历。在算法上,JRaiser Loader采取自顶向下的遍历方式以及自底向上的通知方式。假设有A、B、C三个模块,A依赖于B,B依赖于C。当通过加载A模块时,其加载过程如下(红色箭头部分为异步流程):