在我提到文件名之前,requirejs怎么知道加载一个必需的js文件?

时间:2017-02-11 05:57:17

标签: javascript requirejs

我正在寻找@Domenic使用requirejs的简单示例,从这个答案: simple example for using require.js 我在这里包括。

shirt.js:

define({
    color: "black",
    size : "large"
});

logger.js:

define(function (require) {
    var shirt = require("./shirt");

    return {
        logTheShirt: function () {
            console.log("color: " + shirt.color + ", size: " + shirt.size);
        }
    };
});

main.js:

define(function (require) {
    var shirt = require("./shirt");
    var logger = require("./logger");

    alert("Shirt color is: " + shirt.color);
    logger.logTheShirt();
});

main.html中:

<script data-main="../js/main" src="../js/require.js"></script>

有一些非常奇怪的事情: 在main.js中使用shirt.color的位置, shirt.js和logger.js刚被安排加载,异步(我推测), 所以shirt.js还没有被读过。我认为加载是异步的原因是我的印象是同步加载在chrome中的javascript中几乎是非法的(XMLHttpRequest仍然有一个同步的选项,但如果使用它,它会在chrome控制台Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience.上发出警告)。

然而,这个小应用似乎可靠,可行。 如果我用引用另一个资源的URL替换"./shirt.js",它甚至可以正常工作 世界的一面,我在加载html页面之前清除了我的浏览器缓存。

这怎么可能?

如果我看一下chrome dev控制台中的时间,那么看起来耗时的shirt.js会加载 实际上发生了之前请求它甚至启动的函数。 即不知何故,它知道在程序中的任何内容之前加载shirt.js,根本就是“./shirt”。

似乎这里有一些非常鬼鬼祟祟的魔法。 所以我很想知道:

  1. 在遇到任何要求之前,needjs怎么知道加载shirt.js?
  2. 在多大程度上可以依赖它?
  3. 如何修改这个例子以避免依赖偷偷摸摸的魔法?
  4. 对于我们这些不信任偷偷摸摸的魔法的人,有没有办法在使用requirejs时禁用它?

1 个答案:

答案 0 :(得分:1)

  

requirejs怎么知道在任何要求之前加载shirt.js?

这是你的模块:

define(function (require) {
    var shirt = require("./shirt");
    var logger = require("./logger");

    alert("Shirt color is: " + shirt.color);
    logger.logTheShirt();
});

调用define时,RequireJS检测到没有依赖项列表时调用它。因此,它会扫描您为require调用实例传递的回调,它采用单个参数,这是一个字符串文字,并且它抓取单个参数并将这些参数列表作为模块的依赖项列表。您的模块在功能上与此相同:

define(["require", "./shirt", "./logger"], function (require) {
    var shirt = require("./shirt");
    var logger = require("./logger");

    alert("Shirt color is: " + shirt.color);
    logger.logTheShirt();
});

因此在实际调用回调之前会加载./shirt./logger。然后,当执行require("./shirt")require("./logger")时,它们只是在已加载模块的映射中查找。 (并且,正因为如此,在传递给require的回调中调用时,使用单个字符串参数调用define只能 。否则,你会得到可怕的{{} 3}}错误。)

此功能称为“CommonJS sugar”,因为使用单个参数(即字符串并返回模块)的require调用是CommonJS本身支持的。本机AMD require调用将一组依赖项作为第一个参数和一个可解决的模块传递给它的可选回调。

  

这在多大程度上可以依赖?

我依靠CommonJS糖可以毫无问题地使用数百个模块。

此模式的一个限制是,如果您尝试将除字符串文字之外的内容传递给require。例如,如果你这样做:

define(function (require) {
    var shirtName = "./shirt";
    var shirt = require(shirtName);

这会甩开RequireJS。它不会检测到您的模块需要./shirt模块,并且您将收到我上面提到的错误。

  

如何修改这个例子以避免依赖偷偷摸摸的魔法?

define(["./shirt", "./logger"], function (shirt, logger) {
    alert("Shirt color is: " + shirt.color);
    logger.logTheShirt();
});
  

对于我们这些不信任偷偷摸摸的魔法的人,有没有办法在使用requirejs时禁用它?

您无法使用任何标志来阻止RequireJS支持CommonJS糖。如果你想避免在你自己的代码中依赖它,你可以编写你的模块,就像我在前面的代码片段中所示:使用依赖项列表作为第一个参数调用define,并将模块作为参数获取你的回调。

话虽如此,我认为没有充分理由这样做。我已经使用了RequireJS多年,如果有的话,我一直在使用define代码依赖于CommonJS糖的代码列表。我发现后者在各种开发工具中效果更好。