seajs原理解析
一:
1.本文是基于seajs2.2.1编写的,之后版本应该大同小异
2.本文仅代表个人观点,如有理解错误,敬请指出,大家一起学习
二:
1.首先放一张我画的流程图
这是我理解的seajs的基本的所有流程,接下来通过代码结合该流程图讲解下我的理解
2.1.首先从seajs.use开始,如以下图的代码所示
首先执行preload方法,看preload方法,其实就是执行module.use方法,所以我们直接从module.use讲起,先获取module,如果没有就新建,并且缓存在cachedMods中,定义callback方法(之后会讲),然后执行module.load方法(注意module.get方法,是把所有的ids当做deps传入的)
2.2.module.load方法
看代码,第一次进来,该模块的status还是0,第一个if判断主要是为了require同一个模块多次时只需加载一次(已经loading的只需等他自己的回调),然后resolve方法是用来解析路径的,emit该方法是用来触发seajs自己定义的事件的,seajs.on可以定义事件,这里会触发load事件(如果有自定义),之后的for循环是若主模块的依赖模块还没被加载,就在被依赖的模块的waiting数组中放入主模块的key值以及被依赖次数。当主模块的remain为0时,就加载自身代码,否则往下进入Module.prototype.fetch方法
2.3.Module.prototype.fetch
首先改变状态为fetch,fetchinglist和callbackList分别用来判断和缓存模块,把sendrequest方法存入requestCache返回回去(在sendrequest中有吧onrequest方法传了进去(待会会调用到)),然后module.load方法继续执行,看2.2的图最后一个for循环遍历所有依赖模块执行sendrequest.
module.status更新为FETCHING.
2.4.sendRequest(seajs.request) 以及addonload
执行request方法,创建一个节点,在该节点上加上一个onload方法,然后插入该节点,插入后会执行插入的代码,一般我们是这么写seajs的,如下
sea.use('a',function(){}); define(function(require,exports,module){var b require('b'); ...;})
所以插入会执行define的方法,define方法主要作用是更新deps和factory,他会根据正则匹配把所有require里面的内容提出来,找到绝对路径,再把factory缓存下来,便于之后执行。
(这里举个例子,如上面的代码,主模块a一开始的deps为他自身a,当a模块load进来,执行define函数,a的deps就更新为b了)
然后就执行addonload中的callback方法
2.5.onRequest--> module.load
见2.3的图,主要的作用是让他的子模块执行module.load方法,如果子模块也有依赖,则重复上述步骤,如果没有,则会进入Module.prototype.onload方法
module.status更新为SAVED-->module.status更新为LOADING
2.6.Module.prototype.onload
mod.callback是当只有使用seajs.use时定义的,可以认为只有主模块会执行,for循环写的是当被依赖的模块加载一次,主模块的remain就减去相应的数量,直至为0,主模块进入onload方法,由于主模块youcallback,执行mod.callback()
module.status更新为LOADED
2.7mod.callback()-->module.prototype.exec(部分见图2.1)
图2.1的图中可以看出,模块会先执行module.prototype.exec后会执行自定义的callback方法。
module.prototype.exec就是执行factory方法,也就是define时定义的方法,这里有几个方法,require方法主要作用是执行引进来的方法(已经在前面把他加载进来了,但是还未执行,执行factory时顺序执行require方法,被返回exports)
require.async异步加载,其本质就是module.use就是在执行时新建了一个模块(重走了上述步骤)
exports就是暴露出来的方法,到这里mod.status就变成status.executed了,到这里所有的就都结束了。
module.status更新为EXECUTING-->module.status更新为EXECUTED.
3.结语
有一些里面的方法及细节没有讲到,主要讲了大致流程,如果有错误,请帮忙指出及修改,谢谢!