源码分析系列 - sea.js

xiaoxiao2021-02-27  355

当前版本: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 引入依赖。这可以让依赖内置,开发者只需关心当前模块的依赖

转载请注明原文地址: https://www.6miu.com/read-4647.html

最新回复(0)