• 30分钟 带你浅入seajs源码


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

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

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

    结束前戏  直入主题  哈哈

    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

    demo

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

    //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身上

    大家看

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

    config函数

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

    use函数

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

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

     

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

    然后fetch方法里 会把加载的模块的真实地址为key 生成requestCache[emitData.requestUri]  = sendRequest ,赋值内部函数 sendRequest,然后sendRequest调用内部onRequest
     

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

    然后执行request函数 addOnload 会绑定模块获取成功的onload和onerror函数,392,script真正插入到页面中。

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

    define,require函数

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

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

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

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

    exports

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

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

    exports.module

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

    好剩下

    require.async  

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

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

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

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

  • 相关阅读:
    bilibili 高并发实时弹幕系统的实现
    主流深度学习框架对比
    完整的视频直播系统
    一个简单的直播demo for java
    流媒体知识 wiki
    Entity Framework 6 暂停重试执行策略
    泛型的资源释放
    Entity Framework异步查询和保存
    Entity Framework中的连接管理
    了解Entity Framework中事务处理
  • 原文地址:https://www.cnblogs.com/skyweaver/p/5118530.html
Copyright © 2020-2023  润新知