当前版本:3.0.1
来源:https://github.com/seajs/seajs
运行docs文件夹下index.html(官方提供的demo,我是本地用webstorm运行的,访问链接http://localhost:63342/seajs-master/docs/index.html?_ijt=9s99vov9igsbmqk9a4r89sh8b4),控制台直接看下seajs对象
Module: function Module(uri, deps) // 模块
STATUS: Object // 模块状态
FETCHING: 1 // 当前模块正在被加载
SAVED: 2 // 当前模块加载完成并已保存到cachedMods
LOADING: 3 // 模块依赖正在加载
LOADED: 4 // 模块依赖已经加载完成
EXECUTING: 5 // 该模块正在执行
EXECUTED: 6 // 模块执行完成(`module.exports`可用)
ERROR: 7 // 404,找不到模块
define: function (id, deps, factory) // 模块定义的函数(模块id,依赖,模块)
cmd: Object // Module.define.cmd = {} 源码中设置为空对象,暂时没明白其用处
get: function (uri, deps) // 获取一个已存在的模块(从cachedMods中获取)或创建一个新的模块(new Module(uri, deps)并根据uri存入cachedMods)
resolve: function (id, refUri) // 将ID解析为uri
save: function (uri, meta) // 将'元数据'保存到cachedMods
use: function (ids, callback, uri) // 加载匿名模块
cache: Object // 缓存的模块(包含加载方式)
http://localhost:63342/seajs-master/docs/_use_0: Module
http://localhost:63342/seajs-master/docs/assets/main.js: Module
http://localhost:63342/seajs-master/docs/assets/main.js_async_1: Module
https://a.alipayobjects.com/gallery/jquery/1.8.2/jquery.js: Module
config: function (configData) // 配置函数,会合并默认配置和自定义配置
data: Object
alias: Object // 模块别名
jquery: "gallery/jquery/1.8.2/jquery.js"
seajs-debug: "https://raw.github.com/seajs/seajs-debug/1.1.1/dist/seajs-debug.js"
base: "http://localhost:63342/seajs-master/dist/" // 用于id2uri解析的根路径
charset: "utf-8" // 请求文件的字符集
cid: function cid() // 内置计数器,拼接到uri后,用作清除缓存
cwd: "http://localhost:63342/seajs-master/docs/" // 当前工作目录
dir: "http://localhost:63342/seajs-master/dist/" // 同base
events: Object //
fetchedList: Object //
http://localhost:63342/seajs-master/docs/assets/main.js: true
https://a.alipayobjects.com/gallery/jquery/1.8.2/jquery.js: true
loader: "http://localhost:63342/seajs-master/dist/sea-debug.js" // sea.js全路径
paths: Object //
gallery: "https://a.alipayobjects.com/gallery"
emit: function (name, data) // 事件触发函数,触发所有绑定的回调。 除了事件名称之外,回调函数接收与`emit`相同的参数
off: function (name, callback) // 删除事件。 如果“callback”未定义,请删除事件的所有回调。 如果“event”和“callback”都未定义,请删除所有事件的所有回调
on: function (name, callback) // 事件绑定
request: function request(url, callback, charset, crossorigin) // 用于请求脚本和样式文件的实用程序(源码中判断了是否是H5环境)
require: function (id) // 引入模块,返回模块暴露的函数mod.exports
resolve: function id2Uri(id, refUri) // 解析模块id
use: function (ids, callback) // 调用module.use
version: "3.0.1"
模块入口函数define (id, deps, factory)(见sea-debug.js 1004~1056)
1.判断入参,factory必须
2.通过正则表达式获取模块依赖
// Parse dependencies according to the module factory code
if (!isArray(deps) && isFunction(factory)) {
deps = typeof parseDependencies === “undefined” ? [] : parseDependencies(factory.toString())
}
如下
function func(require, exports) {
var a = require.async('./a', function(){});
var b = require('./b');
var c = require('./c');
}
parseDependencies通过一系列的操作,从factory中解析出func依赖的依赖模块数组[“./b”, “./c”](注意:异步加载的模块,没有被解析出来,即表示加载当前模块时并不强制依赖异步模块)
定义模块元数据 meta (见sea-debug.js 1032)
var meta = {
id: id,
uri: Module.resolve(id),
deps: deps,
factory: factory
}
关于模块id(标准参考Module Identifiers),简单说来就是作为一个模块的唯一标识。
出于学习的目的,我将它们翻译引用在这里:
1. 模块标识由数个被斜杠(/)隔开的词项组成;
2. 每次词项必须是小写的标识、“.”或“..”;
3. 模块标识并不是必须有像“.js”这样的文件扩展名;
4. 模块标识不是相对的,就是顶级的。相对的模块标识开头要么是“.”,要么是“..”;
5. 顶级标识根据模块系统的基础路径来解析;
6. 相对的模块标识被解释为相对于某模块的标识,“require”语句是写在这个模块中,并在这个模块中调用的。
uri是通过id2Uri根据id匹配得到的(见sea-debug.js 241~257)
3.Module.save 保存当前模块
- 根据uri从cachedMods中获取模块,若不存在,则创建模块
- 若模块已被保存,则不会被覆盖
模块加载过程
当前模块在子模块完全加载执行完成后,才会执行
1. Module.prototype.fetch 通过fetch方法,开始整个加载流程,状态初始化为FETCHING;
2. 当模块加载成功将调用load方法,否则调用error方法,将状态置为ERROR
3. Module.prototype.load 通过load方法,开始加载子模块,状态由SAVED到LOADING;
4. Module.prototype.onload 当子模块都加载完成后都会调用onload方法,状态由LOADING到LOADED;
5. Module.prototype.exec 加载过程都结束了,开始执行模块,状态由EXECUTING到EXECUTED;
总结
sea.js是commonJS规范的一种实现,前端模块化为了能够解决:
1. 命名冲突
2. 文件依赖
在sea.js中:
1. 通过exports暴露模块接口,彻底解决命名冲突的问题;
2. 通过require 引入依赖。这可以让依赖内置,开发者只需关心当前模块的依赖