commonJS,定义了一种同步加载脚本的规范。对于浏览器端而言,因为js脚本都是在远端,用同步的方式可能会长时间阻塞线程。因此,浏览器端的js加载器并不会严格按照commonJS来做。seajs作为一个试图遵循commonJS规范的加载器,是在规范的基础上在外面包一层define,来异步加载js,以下是seajs官网的一个例子:
// 所有模块都通过 define 来定义 define(function(require, exports, module) { // 通过 require 引入依赖 var $ = require(‘jquery‘); var Spinning = require(‘./spinning‘); // 通过 exports 对外提供接口 exports.doSomething = ... // 或者通过 module.exports 提供整个接口 module.exports = ... });
define为回调提供一个获取模块的函数require、两个提供对外接口的对象exports和module。可以看到,模块的依赖是通过调用require来声明的。seajs会用正则把依赖的模块抓取出来,进行加载。为了正确的抓取,seajs定义了一些书写规范。定义模块之后,使用seajs.use使用定义的模块。
requirejs作为一个遵循AMD规范的加载器。其在全局内定义了两个变量,define和require。可以用以下方式定义一个模块:
define(‘module‘,["alpha"], function (alpha) { return { verb: function(){ return alpha.verb() + 2; } }; });
同样也可以用类似seajs那样的定义方式。requirejs用以下方式引用一个模块:
require([‘module‘],function(module){ console.log(module); }) ;
对于seajs和requirejs,一个js文件内只能有一个define函数,也就是说一个js文件对应一个模块。requirejs会在加载完一个模块后,马上执行。而seajs会在加载完执行require时执行模块。
seajs和requirejs还有一些不同。requirejs有shim机制去支持那些不符合AMD规范的模块,seajs本来没有shim机制,之后又加上,最新版又删除了这个功能。requirejs支持webworker,seajs需要第三方的插件支持。
如果需要实现一个加载器,最需要处理的是模块之间的触发关系。一个模块如果依赖别的模块,就需要等到依赖的模块都准备好了,该模块才处于可用的状态。依赖的模块也有可能有其所依赖的模块。所以需要建立一个触发的机制,让模块在已准备的状态下触发对其依赖的模块,使其检查自身的依赖模块是否都已准备好。seajs和requirejs对这个的实现方式有所不同。这里是我实现的一个版本:github地址。