SeaJS 是一个模块加载器,模块加载器需要实现两个基本功能:
- 实现模块定义规范,这是模块系统的基础。
- 模块系统的启动与运行。
define参数
在 CMD 规范中,一个模块就是一个文件。代码的书写格式如下:
define(factory) |
- factory 为对象、字符串时,表示模块的接口就是该对象、字符串。
- factory 为函数时,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory默认会传入三个参数:require、exports 和 module。
// factory 为对象
factory参数
factory参数的使用如下:
require:Function
-
require是一个函数方法,用来获取其他模块提供的接口,而且是同步往下执行。require的模块不能被返回时,应该返回null。
-
require.async(id, callback?):用来在模块内部异步加载模块,并在加载完成后执行指定回调。require的模块不能被返回时,callback应该返回null。callback接受返回的模块作为它的参数。
-
require.resolve(id):不会加载模块,只返回解析后的绝对路径
为什么那么死规定?!
首先你要知道SeaJS 是如何知道一个模块的具体依赖的。SeaJS 通过 factory.toString() 拿到源码,再通过正则匹配 require 的方式来得到依赖信息。这也是必须遵守 require 书写约定的原因。
exports:Object
用来在模块内部对外提供接口。
exports 仅仅是 module.exports 的一个引用。在 factory 内部给 exports 重新赋值时,并不会改变 module.exports 的值。因此给 exports 赋值是无效的,不能用来更改模块接口。
module:Object
- module.uri:解析后的绝对路径
- module.dependencies:模块依赖
- module.exports:暴露模块接口数据,也可以通过 return 直接提供接口,因个人习惯使用。
- 对 module.exports 的赋值需要同步执行,慎重放在回调函数里,因为无法立刻得到模块接口数据。
三种类型的标识:
- 相对标识:以 . 开头(包括.和..),相对标识永远相对当前模块的 URI 来解析。
- 顶级标识:不以点(.)或斜线(/)开始, 会相对模块系统的基础路径(即 SeaJS配置 的 base 路径)来解析。
seajs.config({
base: 'http://code.jquery.com/'
});
// 在模块代码里:
require.resolve('jquery');
// 解析为 http://code.jquery.com/jquery.js
- 普通路径:除了相对和顶级标识之外的标识都是普通路径,相对当前页面解析。绝对路径和根路径也是普通路径。绝对路径比较容易理解。根路径是以“/”开头的,取当前页面的域名+根路径,
如下所示:
/js/b
可省略后缀.js,但是”.css” 后缀不可省略。
模块系统的启动与运行
直接使用 script 标签同步引入sea.js文件后,就可以使用seajs.use(id, callback?)在页面中加载模块了!
通过define定义许多模块后,得让它们能跑起来,如下:
最佳实践:
- seajs.use 理论上只用于加载启动,不应该出现在 define 中的模块代码里。
- 为了让 sea.js 内部能快速获取到自身路径,推荐手动加上 id 属性:
1
|
<script src="../gb/sea.js" id="seajsnode"></script>
|
Sea.js 的调试接口
讲到seajs.use,当然要提一下Sea.js 的调试接口。
- seajs.cache:Object,查阅当前模块系统中的所有模块信息。
- seajs.resolve:Function,利用模块系统的内部机制对传入的字符串参数进行路径解析。
- seajs.require:Function,全局的 require 方法,可用来直接获取模块接口。
- seajs.data:Object,查看 seajs 所有配置以及一些内部变量的值。
- seajs.log:Function,由 seajs-log 插件提供。
- seajs.find:Function,由 seajs-debug 插件提供。
模块加载大体流程
模块加载大体流程:
文字描述:
- 通过 use 方法来加载入口模块,并接收一个回调函数, 当模块加载完成, 会调用回调函数,并传入对应的模块作为参数。
- 从缓存或创建并加载 来获取到模块后,等待模块(包括模块依赖的模块)加载完成会调用回调函数。
- 在图片虚线部分中,加载factory及分析出模块的依赖,按依赖关系递归执行 document.createElement(‘script’) 。
与RequireJS的主要区别
遵循的规范不同
RequireJS 遵循 AMD(异步模块定义)规范,SeaJS 遵循 CMD (通用模块定义)规范。
factory 的执行时机不同
SeaJS按需执行依赖避免浪费,但是require时才解析的行为对性能有影响。
SeaJS是异步加载模块的没错, 但执行模块的顺序也是严格按照模块在代码中出现(require)的顺序。
RequireJS更遵从js异步编程方式,提前执行依赖,输出顺序取决于哪个 js 先加载完(不过 RequireJS 从 2.0 开始,也改成可以延迟执行)。如果一定要让 模块B 在 模块A 之后执行,需要在 define 模块时申明依赖,或者通过 require.config 配置依赖。