上个星期写了浅入requirejs的,  大家都知道 require是AMD规范(Asynchronous Module Definition)

来  今天我们一起看看 CMD规范(Common Module Definition) 的seajs 是怎样实现的

seajs比require写的简单, 源码几乎是require的一半,gzip后差距是拉近了,但是仍觉得大。
(最近对size很敏感 ,因为领导 大领导抱怨我们h5站点打开慢,今年我们逐步做提速的事情, 我心里暗下一个目标,不管业务简单复杂 3G及以上用户,我要做到全站秒开 做到了跟大家分享一下 哈哈)
30分钟 带你浅入seajs源码

 

结束前戏  直入主题  哈哈

sea里面一共就用到几个api

sea.config   ------        配置函数
sea.use       ------       加载 并执行模块(可以是多个)
define         ------       定义模块
require        ------       同步引入模块
require.async  ------    异步引入模块
exports           ------   导出单个属性
module.exports   ----- 导出整个模块

 

详细用法 :http://www.zhangxinxu.com/sp/seajs/docs/zh-cn/cheatsheet.html#exports

目录结构很简单 定义了一个main.js  2个define的 模块

30分钟 带你浅入seajs源码

//main.js
// 所有模块都通过 define 来定义
define(function(require, exports, module) {

    // 通过 require 引入依赖
    var code = require('module/code');
    var game = require('module/game');

    console.log('code' , code);
    console.log('game' , game);

    code.codeAction();
    game.gameAction();

});
//code.js
define(function(require, exports, module) {

    exports.name = 'code';
    exports.skill = 'play';
    exports.codeAction = function() {
        console.log('coding');
    };

    // 或者通过 module.exports 提供整个接口
  /*  module.exports = {
        codeAction: function() {
            console.log('coding');
        }
    }*/


});
//game.js
define(function(require, exports, module) {

    // 或者通过 module.exports 提供整个接口
    module.exports = {
        gameAction: function() {
            console.log('gaming');
        }
    }


});

 

 

首先我觉得sea的源码有点有意思的地方,他真的是  “那里用到, 那里定义”  看过我上一篇requrejs的文章的同学知道 我喜欢先把代码叠起来 一览众山小,这招用不了在sea身上

大家看

30分钟 带你浅入seajs源码

 

像很多人都有这么一个强迫症,就是 所以定义都放在最开始的地方统一定义了, sea说 我偏不, 我哪里用到, 那里定义  哈哈  气死处女座

 

config函数

for in 每一个属性, 处理好后 挂在 闭包全局的data里

30分钟 带你浅入seajs源码

 

use函数

首先 seajs.use 会调用 Module.use , 然后 cid是每次调用自动++ 生成全局唯一标记,

Module.use 第一行, 初始化mod的属性, 然后真正处理是mod.load(),注意 这里的挂了callback函数 还有 callback后删除变量 释放内存 

 30分钟 带你浅入seajs源码

30分钟 带你浅入seajs源码

30分钟 带你浅入seajs源码

 

然后 module.load里 会判断这个模块是否加载过, 如果没有加载过,会调用fetch方法,加载过 直接调用m.load() 

30分钟 带你浅入seajs源码

 

 

然后fetch方法里 会把加载的模块的真实地址为key 生成requestCache[emitData.requestUri]  = sendRequest ,赋值内部函数 sendRequest,然后sendRequest调用内部onRequest
30分钟 带你浅入seajs源码 

758line fetch函数生成模块的请求关系后, 然后 留意768 真正执行这个fetch函数

30分钟 带你浅入seajs源码

 

然后执行request函数 addOnload 会绑定模块获取成功的onload和onerror函数,392,script真正插入到页面中。
30分钟 带你浅入seajs源码

顺便补充一句, sea很奇怪, 加载成功use后,会remove这个script, 我没搞懂这个用意何在, 节省了页面一个script?

30分钟 带你浅入seajs源码

 

define,require函数

因为2个函数 是有关系的, 可以是你中有我,我中有你, 所以就不拆开了。
先看define ,前面几行是处理参数的, 过

主要看deps,这里其实就是解析define里的关键字,是否含有require,看控制台输出

这个470行到672行 其实就是require的实现, 纯粹是个体力 、严谨、 技巧活 ,各种字符串处理,各种正则匹配, 没有遇到的场景,写不出来, 纯粹个人见解。 

30分钟 带你浅入seajs源码

30分钟 带你浅入seajs源码

 

然后再执行onRequest方法, 再次执行m.load方法解析modules里的依赖模块,如果存在就像刚才use里获取main一样,获取模块,执行callback

30分钟 带你浅入seajs源码

 

 

exports

exports其实很简单的, 其实就是一个空的obj,然后把你需要的属性都挂在这个exports对象里面

每一个define里都有一个属于自己的exports  不会污染别的模块

30分钟 带你浅入seajs源码

30分钟 带你浅入seajs源码

 

exports.module

不用说你也懂了吧? 就是所有属性都只能写在module里,看我上图exports下面有个exports.module的注释, 其实就是换个写法罢了

好剩下

require.async  

其实就是use的实现,加一个callback而已

看源码  ,这么聪明的你 ,肯定一眼就懂了

30分钟 带你浅入seajs源码

 

 

好  写了一个下午了, 有点累, 准备一下去健身房, 楼主很瘦  怕猝死  如果你知道有很好的增肥方法, 请告诉我  哈哈哈。

最后  如果此文对你有帮助, 记得点赞哦, 你的点赞,是我继续创作的动力

 

相关文章: