使用糖语法动态加载requirejs模块

Rol*_*ink 2 javascript requirejs

嗨,我试图通过获取过滤器列表和迭代数组来加载这些模块,以动态方式加载一些requireJs模块

define(function(require){
var runFilters = function(filters){
    var _ = require('underscore');
    var computedFilters  = getFilters(filters);
    var result = _.every(computedFilters,function(filter){
        return filter();
    });
    return result;
};

var getFilters = function(filters){
    var _ = require('underscore');
    return _.map(filters,function(filter){
        return require('filters/' + filter);
    },this);
}


var register = function(filters,fn){
    return function(){
        var args = Array.prototype.slice.apply(arguments);
        if(runFilters(filters))
            fn.apply(this,args);
    }
}
return{
    register: register
}
});
Run Code Online (Sandbox Code Playgroud)

这给了我错误:Uncaught Error:模块名称"filters/isAuth"尚未加载上下文:_

但是当将其替换为静态方式(仅用于测试)时,它会完美地加载

define(function(require){
    var runFilters = function(computedFilters){
        var result = _.every(computedFilters,function(filter){
            return filter();
        });
        return result;
    };

    var getFilters = function(filters){
        var _ = require('underscore');
        return _.map(filters,function(filter){
            console.log(filter);
            return require('filters/' + filter);
        },this);
    }


    var register = function(filters,fn){
        var cachedFilters = [];
        cachedFilters.push(require('filters/isAuth'));
        return function(){
            var args = Array.prototype.slice.apply(arguments);
            if(runFilters(cachedFilters))
                fn.apply(this,args);
        }
    }
    return{
        register: register
    }
});
Run Code Online (Sandbox Code Playgroud)

这也给了我错误

cachedFilters.push(require('filters'+'/isAdmin'));
Run Code Online (Sandbox Code Playgroud)

Lou*_*uis 7

您已经遇到RequireJS对CommonJS语法支持的限制.这是交易.当RequireJS定义一个模块时,它会查看你给出的工厂函数(回调)define.它寻找这种模式:

/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g
Run Code Online (Sandbox Code Playgroud)

这符合require通话就像var foo = require('foo');对于每一次这样的呼叫,它增加了所需要的模块,你的模块依赖关系的列表.所以,例如,像:

// The `require` parameter must be present and is filled with something useful
// by RequireJS.
define(function (require) {
    var foo = require('foo');
    var bar = require('bar');
    ...
});
Run Code Online (Sandbox Code Playgroud)

被这样对待:

define(['require', 'foo', 'bar'], function (require) {
    var foo = require('foo');
    var bar = require('bar');
    ...
});
Run Code Online (Sandbox Code Playgroud)

如果仔细查看上面的正则表达式,您会发现它只匹配require具有单个参数(即文字字符串)的调用.所以这样的事情是require("something" + somevar)行不通的.在进行此转换时,RequireJS完全忽略它们.

通过更改正则表达式无法解决该问题.RequireJS的核心是一个异步加载模块的系统.require使用单个字符串文字的调用形式是糖,以允许更容易移植根据CommonJS模式设计的模块,以及喜欢这种风格的人(即使他们没有移植任何东西).这种类型的调用看起来是同步的,实际上并不是同步 为了支持计算传递给它的名称的情况,RequireJS必须预测值是什么.

如果你想完全自由地在你的代码中加载你想要的任何模块而不提前知道名称是什么,那么你必须使用异步require调用(require([computed_value], function(mod) {...})),这意味着你的代码必须是异步的.如果你想要加载一组有限的模块,并且总是可以加载它们,那么你可以使用文字字符串来要求它们:

define(function (require) {
    require("filters/isAdmin");
    require("filters/b");
    require("filters/c");
    require("filters/d");
    ...
});
Run Code Online (Sandbox Code Playgroud)

RequireJS将进行上述转换,并require使用计算值进一步调用,这些值将解析为模块中早期所需的名称之一,不会失败.