前言:上一篇对Seajs及其使用做了简单的介绍,这一章开始正式接触Seajs的源码。
Sea.js 的所有代码都通过 GitHub 管理,项目地址:https://github.com/seajs/seajs
其源码放在src目录下。
目录结构:
scr目录结构:
-------------------------
intro.js -- 全局闭包头部
sea.js -- 基本命名空间
util-lang.js -- 语言增强
util-events.js -- 简易事件机制
util-path.js -- 路径处理
util-request.js -- HTTP 请求
util-deps.js -- 依赖提取
module.js -- 核心代码
config.js -- 配置
outro.js -- 全局闭包尾部
本章主要对module.js模块进行介绍。
代码分析:
module.js作为整个Seajs的核心,无疑是十分重要的。Seajs作为一个模块加载器,其所有的模块都会作为一个Module对象存储在seajs.cache
中。通过seajs.cache
,我们可以查阅当前模块系统中的所有模块信息。
一个模块在加载过程中必然会经历以下几个阶段:
var STATUS = Module.STATUS = {
// 1 - The `module.uri` is being fetched
FETCHING: 1, //开始加载当前模块
// 2 - The meta data has been saved to cachedMods
SAVED: 2, //当前模块加载完成并保存模块数据
// 3 - The `module.dependencies` are being loaded
LOADING: 3, //开始加载依赖的模块
// 4 - The module are ready to execute
LOADED: 4, //依赖模块已经加载完成
// 5 - The module is being executed
EXECUTING: 5, //当前模块执行中
// 6 - The `module.exports` is available
EXECUTED: 6, //当前模块执行完毕
// 7 - 404
ERROR: 7 //出错
}
同时,我们在内存中使用Module
对象来维护模块的信息:
function Module(uri, deps) {
this.uri = uri
this.dependencies = deps || []//依赖模块ID列表
this.deps = {} // Ref the dependence modules
this.status = 0
this._entry = []//在模块加载完成之后需要调用callback的模块
}
对应模块加载的几个阶段状态,总结模块加载的大致过程如下:
模块方法 | 方法说明 | 状态变化 |
---|---|---|
seajs.use | 在页面上启动模块系统,加载一个或多个模块 | |
Module.use: | 开始加载整个流程 | 状态变化:FETCHING到SAVED |
Module.prototype.load | 开始加载子模块 | 状态变化:SAVED到LOADING |
Module.prototype.onload | 子模块加载完成时调用 | 状态变化:LOADING到LOADED |
Module.prototype.exec | 加载过程结束,开始执行模块 | 状态变化:EXECUTING到EXECUTED |
接下来,我们来具体的看一下Seajs模块加载的具体过程:
1.首先,我们来看一下seajs.use
,这是整个模块加载的启动器。
/**
* 用来在页面中加载一个或多个模块
* @param ids 模块名 (文件路径)
* @param callback 回调函数
*/
seajs.use = function(ids, callback) {
Module.use(ids, callback, data.cwd + "_use_" + cid())
return seajs
}
示例如下:
seajs.use("./main",function(main){
main.init();
})
我们可以传入想要加载的模块名以及回调函数,进行模块的加载。
2.接下来,我们来看一下Module.use
方法
// Use function is equal to load a anonymous module load相当于执行一个匿名module
/**
*开始整个加载流程,状态初始化为FETCHING到SAVED
* @param ids 依赖模块
* @param callback 模块id
* @param uri 获取uri模块
*/
Module.use = function (ids, callback, uri) {
var mod = Module.get(uri, isArray(ids) ? ids : [ids])
mod._entry.push(mod)
mod.history = {}
mod.remain = 1 //未加载的模块个数
mod.callback = function() {
var exports = []
var uris = mod.resolve()
for (var i = 0, len = uris.length; i < len; i++) {
exports[i] = cachedMods[uris[i]].exec()
}
if (callback) {
callback.apply(global, exports)
}
delete mod