源码分析系列 - sea.js

当前版本: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 保存当前模块
  1. 根据uri从cachedMods中获取模块,若不存在,则创建模块
  2. 若模块已被保存,则不会被覆盖

模块加载过程

当前模块在子模块完全加载执行完成后,才会执行
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 引入依赖。这可以让依赖内置,开发者只需关心当前模块的依赖

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值