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

时间:2014-02-14 17:37:31

标签: 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
}
});

这给我发错:未捕获错误:模块名称“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
    }
});

这也给我错误

cachedFilters.push(require('filters'+'/isAdmin'));

1 个答案:

答案 0 :(得分:7)

你遇到了RequireJS对CommonJS语法支持的限制。这是交易。当RequireJS定义模块时,它会查看您为define提供的工厂函数(回调)。它寻找这种模式:

/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g

这匹配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');
    ...
});

这样对待:

define(['require', 'foo', 'bar'], function (require) {
    var foo = require('foo');
    var bar = require('bar');
    ...
});

如果仔细查看上面的正则表达式,您会发现它只会匹配{em>单参数的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");
    ...
});

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