• 读RequireJS — Module


    Module 即模块,来看下RequireJS怎么定义 Module :

    1. 简单的名值对

    // Inside file my/shirt.js:
    define({
        color: "black",
        size: "unisize"
    });

    2. 定义成一个Function

    // my/shirt.js now does setup work
    // before returning its module definition.
    define(function () {
        // Do setup work here
     
        return {
            color: "black",
            size: "unisize"
        }
    });

    3. 如果 Module 需要依赖别的模块,可以写成这样:

    // my/shirt.js now has some dependencies, a cart and inventory
    // module in the same directory as shirt.js
    define(["./cart", "./inventory"], function(cart, inventory) {
            // return an object to define the "my/shirt" module.
            return {
                color: "blue",
                size: "large",
                addToCart: function() {
                    inventory.decrement(this);
                    cart.add(this);
                }
            }
        }
    );

    4. 隐式依赖Function

    define(function(require) {
        var mod = require("./relative/name");
    });

      

    上面这四种比较常用,RequireJS 中的 Module 还有其他的形式,具体可参阅官方文档。

    上面四种方式都用到了define(),接下来我们就来看下define的源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    /**
     * The function that handles definitions of modules. Differs from
     * require() in that a string for the module should be the first argument,
     * and the function to execute after dependencies are loaded should
     * return a value to define the module corresponding to the first argument's
     * name.
     */
    define = function (name, deps, callback) {
        var node, context;
     
        // 可以是匿名模块
        if (typeof name !== 'string') {
            // 调整参数
            callback = deps;
            deps = name;
            name = null;
        }
     
        // 如果模块没有依赖
        if (!isArray(deps)) {
            callback = deps;
            deps = [];
        }
     
        // 如果是一个没有传入依赖的Function,即例4所示
        if (!deps.length && isFunction(callback)) {
            // 通过 callback.toString() 找依赖
            // 为了避免 require(xx) 写在注释中
            // 这里先把注释都去掉,再把require的东东加入deps数组
            //
            // 很变态的一点就是如果callback里写了require
            // 则 callback 必须有形参,不然会被无视
            if (callback.length) {
                callback
                    .toString()
                    .replace(commentRegExp, "")
                    .replace(cjsRequireRegExp, function (match, dep) {
                        deps.push(dep);
                    });
     
                //May be a CommonJS thing even without require calls, but still
                //could use exports, and module. Avoid doing exports and module
                //work though if it just needs require.
                //REQUIRES the function to expect the CommonJS variables in the
                //order listed below.
                // 可能某些模块即使没有调用require,但却仍然要用到exports和module
                // 如果模块仅仅需要require,就应该避免exports和module的开销
                // 注意:依赖的顺序应该确保像下面这样
                //
                // 这里我把中英文都给出了,因为对于这句我一直很疑惑
                // 1个形参 需要 require
                // 大于1个形参 需要 require exports module
                // 1和非1有那么大差别么,请高手指点一下,这句实在很无解
                deps = (callback.length === 1 ? ["require"] : ["require", "exports", "module"]).concat(deps);
            }
        }
     
        // 应用场景:IE6-8,并且是定义一个匿名模块
        // 个人觉得这个判断没有意义,请看下面的注释
        if (useInteractive) {
            node = currentlyAddingScript || getInteractiveScript();
            if (node) {
                if (!name) {
                    name = node.getAttribute("data-requiremodule");
                }
                context = contexts[node.getAttribute("data-requirecontext")];
            }
        }
     
        // 真正定义模块的操作放到script onload函数中执行,有两个好处:
        // 1.如果一个文件定义了多个模块,这样可以防止过早的分析依赖, 而是等拿到所有依赖之后, 统一进行处理
        // 2.如果是定义匿名模块, define执行中我们是不知道 moduleName的, 但在onload函数中却可以知道
        //
        // 这里有个问题,即下面这行代码表示有context就加入context.defQueue,没有就加入globalDefQueue
        // 很明显,context有值的情况仅在IE6-8会出现,
        // 而在onload时,会把globalDefQueue里的东西全部加入context.defQueue,所以加入谁无所谓
        // 而且在onload函数中所有浏览器都可以拿到moduleName,所以下面这句和上面那个if判断都失去意义了
        // 可以写成 globalDefQueue.push([name, deps, callback]);
        (context ? context.defQueue : globalDefQueue).push([name, deps, callback]);
     
        return undefined;
    };

    define() 有三个参数,不传 name 参数表示为匿名模块,匿名只是写法上的匿名,RequireJS 可以通过文件路径确定 moduleName,所以最好别传 name 参数,这样文件目录即使有变动,也不会影响模块的正常使用。

    这里 callback 参数命名很不好,一般都会叫做factory,取名 callback 完全不知所云。  

    所谓的 define 是干嘛的呢 ?

    这个函数用于定义模块,可具名,也可匿名,可有依赖,也可无依赖,factory可以是一个function,也可以是一个object,define 就是为当前的模块绑定一个 factory,当我们要用这个模块的时候,再通过 factory 把它造出来。当然,factory是个object,就不需要再造了。

    可以看到模块不是单独存在的,一般都会依赖别的模块,我们知道,在web开发中, 如果要加载一个资源,都需要在回调函数中进行处理,因为加载是异步的。

    而 CommonJS 想实现同步加载的概念,所以每次加载一个模块,会首先把依赖分析出来,加载完依赖之后,再去执行factory,这样倒也算是一种模拟同步了。

  • 相关阅读:
    DHCP服务器搭建
    linux文件通配符
    NTP服务器搭建
    .Net下MoongoDB的简单调用
    Mac 下安装配置MongoDB讲解
    Redis 介绍学习
    PostgreSQL学习之路一 安装
    CentOS安装PostgreSQL
    离线安装PostgreSQL11.6
    PostgreSQL 安装扩展插件plpython3u执行python,访问页面或者第三方程序
  • 原文地址:https://www.cnblogs.com/zhepama/p/3078392.html
Copyright © 2020-2023  润新知