seajs模块加载机制

本文谈论的代码版本是Sea.js 2.3.0,seajs最新的版本是3.0,3.0版本变动较大.

新事物的出现或多或少的是想改变已有的行为方式,解决遇到的问题。关于这段历史,大家可以看看这几篇文章:why-seajs1why-seajs2

关于seajs原理介绍和分析的文字也有不少,例如:Sea.js是如何工作的?实例解析 SeaJS 内部执行过程 - 从 use 说起、也有人分析了seajs代码中的数据结构:SeaJSV1.1.0-代码结构和数据结构


既然已经有很多优秀的文章介绍seajs了,为什么你还要浪费时间呢?

因为脑子不好使,写作的过程使我审视自己的结论,加深了我对事物的理解。

seajs干嘛的

SeaJS是一个遵循CMD规范的JavaScript模块加载框架,用以实现JavaScript的模块化开发及加载机制

注意关键词:CommonJS规范,模块加载,模块化开发

  • CMD规范全称Common Module Definition,该规范明确了模块的基本书写格式和基本交互规则,即定义了一组模块化开发的接口,具体细节可以参看:CMD 模块定义规范英文 Common Module Definition

  • 有C++,Java,Python开发经验的同学应该很容易理解模块化开发和模块加载的概念,以java为例,类是java的最小开发单位,一个类可以看做是一个最小模块,一个或多个类可以组成一个package,这种组织代码的方式就是模块化开发

  • 当我们在一个类中import另一个package的内容时,import的内容最终会被包含进当前类中,seajs要做的一个事情就是模拟java中import这种模块加载机制。

  • 与服务器端不同,在浏览器端实现模块加载又有其特点:模块(js文件)需要经过网络传输到达用户浏览器,那么何时将js文件下载到用户本地?性能考虑,提前将用到的js文件下载到用户本地是首选,免去了执行期从服务器请求文件消耗的时间,但同时seajs也提供了异步加载模块的功能。

两个核心

1. 模块的依赖加载

如何从服务器获取js文件,这里就不详细解释了,原理就是append script标签的方式。

模块间的关系无非就是依赖和被依赖的关系,具体到两个模块上,有下图三种关系:

  1. a模块依赖b模块
  2. b模块依赖a模块
  3. a,b模块相互依赖
两个模块间的依赖关系

前两种情况很好理解,对于第三种情况,seajs在3.0版本前是不支持循环依赖的,具体表现为模块加载会中断,a.doSomething()并没有执行,3.0的循环依赖处理和node一样了#1382,下面的代码可以用来测试这个问题。

seajs.use("a" , function(a){
    a.doSomething();
});

//a.js
define(function(require, exports , module) {
    var b = require("b");
    exports.doSomething = function() {
        console.log("in a");
    };
});

//b.js
define(function(require, exports, module) {
    var c = require("c");
    exports.doSomething = function() {
        console.log("in b");
    };
});

//c.js
define(function(require, exports, module) {
    var a = require("a");
    exports.doSomething = function() {
        console.log("in c");
    };
});

提炼一下上面描述的内容就是:对于一个模块M,它应该拥有下面的关系

Module{
a: {Module依赖的模块}
b: {依赖Module的模块}
}

在看看seajs中Module的定义:

function Module(uri, deps) {
  this.uri = uri
  this.dependencies = deps || []//我依赖的模块
  this.exports = null
  this.status = 0   //我当前的状态
  this._waitings = {} //依赖我的模块
  this._remain = 0  //我依赖的模块还有多少没有完成加载
}

以一个实际的例子说明一下seajs模块加载的逻辑,如下图:

百度脑图
  • a依赖b和c
  • b依赖d

尽管存在上述依赖,但是a,b,c,d模块download到浏览器端的顺序确是a,b,c,d,而不是d,b,c,a,笨想一下后一种执行顺序也是不可能的,因为模块间的依赖只有download到浏览器端seajs才能进行分析。

概括一下整个加载的流程就是:

自顶向下的download,自底向上的反馈准备就绪。

如何做到的呢?

  1. 主要是Module中的几个属性发挥的作用,模块被download到浏览器端后,按照CMD规范,define函数会被执行,module.define会分析该模块的依赖,记录到dependencies属性中,define函数执行完毕,绑定在script标签上的onload事件会被触发,进而加载当前模块的依赖模块,也就是执行module.load函数,这是一个循环往复的过程。

  2. 假设d模块加载就绪,执行module.load时发现,d模块已无其他依赖,进而执行module.onload, 在module.onload中,通过_waitings属性找到父模块,操作父模块的依赖计数_remain,达到通知父模块的目的。

这是一个完美的反馈系统。

seajs的模块加载可以分为两部分,一部分就是模块加载的过程,另一部分就是模块执行的过程。相比较而言,执行过程就比较简单了,具体可以看源码module.exec这个函数。

下一节分析seajs中模块id的解析原理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容