当前版本: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”](注意:异步加载的模块,没有被解析出来,即表示加载当前模块时并不强制依赖异步模块)
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 引入依赖。这可以让依赖内置,开发者只需关心当前模块的依赖