【问题标题】:Dynamic require in RequireJS, getting "Module name has not been loaded yet for context" error?RequireJS中的动态需求,得到“模块名称尚未加载上下文”错误?
【发布时间】:2013-07-01 01:48:32
【问题描述】:

有没有办法在 RequireJS 中定义一个“动态”加载其他模块的模块?如果是,优化器(r.js)如何理解必须包含模块的方式/时间?

例如,让dynModules 定义名称/路径对的模块:

define([], function () {
    return ['moduleA', 'moduleB']; // Array of module names
});

另一个模块将根据数组动态加载模块。这将不起作用

define(['dyn_modules'], function (dynModules) {
    for(name in dynModules) {   
        var module = require(path); // Call RequireJS require
    }

    // ...
});

...给我:

未捕获的错误:尚未加载模块名称“moduleA” 语境: _。使用要求([]) http://requirejs.org/docs/errors.html#notloaded

我可以解决错误,但它不再是“动态的”:

define(['dyn_modules', 'moduleA', 'moduleB'], function (dynModules) {
    for(name in dynModules) {   
        var module = require(path); // Call RequireJS require
    }

    // ...
});

【问题讨论】:

标签: javascript browser module requirejs r.js


【解决方案1】:

限制与简化的 CommonJS 语法与普通回调语法有关:

由于未知的下载时间,加载模块本质上是一个异步过程。但是,RequireJS 在模拟服务器端 CommonJS 规范时试图为您提供简化的语法。当你做这样的事情时:

var foomodule = require('foo');
// do something with fooModule

在幕后发生的事情是 RequireJS 正在查看您的函数代码的主体并解析出您需要 'foo' 并在您的函数执行之前加载它。但是,当变量或简单字符串以外的任何内容时,例如您的示例...

var module = require(path); // Call RequireJS require

...那么 Require 无法解析并自动转换它。解决方法是转换为回调语法;

var moduleName = 'foo';
require([moduleName], function(fooModule){
    // do something with fooModule
})

鉴于上述情况,这里是您的第二个示例的一种可能的重写以使用标准语法:

define(['dyn_modules'], function (dynModules) {
    require(dynModules, function(){
        // use arguments since you don't know how many modules you're getting in the callback
        for (var i = 0; i < arguments.length; i++){
            var mymodule = arguments[i];
            // do something with mymodule...
        }
    });

});

编辑:根据您自己的回答,我看到您使用的是下划线/lodash,因此使用 _.values_.object 可以简化上述参数数组的循环。

【讨论】:

  • 感谢您的宝贵时间,我在 RequireJS 网站上搜索后找到了解决方案。看我的回答。
  • 我唯一的问题是:使用require(_.values(Config), ...) 是异步代码,对吧?也就是说我需要在require结束时使用回调样式,对吧?
  • 是的,您在回答中使用了回调语法。 require(_.values(Config), function () { 大致相当于我的require(dynModules, function(){。两者都使用字符串数组作为第一个参数,并提供回调函数作为第二个参数。
  • 请注意,除非您在选项中设置 { findNestedDependencies: true },否则这将破坏 requireJS 的编译功能。
  • 如果我想添加怎么办 - require("somemodule");其中 somemodule 是一个 json 文件
【解决方案2】:

回答我自己。来自 RequireJS 网站:

//THIS WILL FAIL
define(['require'], function (require) {
    var namedModule = require('name');
});

这会失败,因为 requirejs 需要确保在调用上面的工厂函数之前加载并执行所有依赖项。 [...] 所以,要么不要传入依赖数组,要么如果使用依赖数组,请列出其中的所有依赖项。

我的解决方案:

// Modules configuration (modules that will be used as Jade helpers)
define(function () {
    return {
        'moment':   'path/to/moment',
        'filesize': 'path/to/filesize',
        '_':        'path/to/lodash',
        '_s':       'path/to/underscore.string'
    };
});

加载器:

define(['jade', 'lodash', 'config'], function (Jade, _, Config) {
    var deps;

    // Dynamic require
    require(_.values(Config), function () {
        deps = _.object(_.keys(Config), arguments);

        // Use deps...
    });
});

【讨论】:

  • 不,modules 应该在另一个模块中定义,即配置文件。顺便说一句,它工作得很好。
  • 看来关键还是CommonJS同步语法到RequireJS回调语法的转换。
  • @explunit 你能更好地解释一下你的意思吗?我只需要在 Jade(作为助手)中提供一些模块(用于浏览器),并且我需要它是动态的。
  • 更新了我的答案以澄清。这两个答案都有效,只是想向任何未来的读者解释 RequireJS 在幕后到底发生了什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-09-26
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多