RequireJS:模块嵌套需求中的动态依赖关系

IAR*_*ARI 4 javascript requirejs

假设有一个函数返回包含动态依赖关系的数组.然后在模块B中使用这些依赖关系.另一个模块A又使用模块B.

A.js

define([B], function(moduleB){
    moduleB.m();
})
Run Code Online (Sandbox Code Playgroud)

B.js:

define([ dep1, dep2 ], function( dep1, dep2 ) {

    var dyndeps = dep2.getDynDeps();
    var moduleB = {}

    require(dyndeps, function() {
        moduleB.m = function() { ... };
    })

    return moduleB;

});
Run Code Online (Sandbox Code Playgroud)

这种方法的问题是,内部需求是异步执行的,因此方法m不能及时获得.

art*_*rtm 9

由于B.m是由动态依赖B提供的,因此应该提供一个等待它可用的接口.有许多插件可以允许,例如rq(使用Q promises),promise(使用jquery,Q,RSVP或ES6 promises),promiseme(自包含?).

使用其中之一,B不会返回moduleB,而是一个承诺.嵌套require调用将使用complete解析promise moduleB.A需要<PLUGIN>!B.例如使用promisejquery:

// A.js
define(["promise!B"], function(moduleB){
    // B is complete now
    moduleB.m();
})

// B.js
define([ "dep1", "dep2", "jquery" ], function( dep1, dep2, $ ) {

    var dyndeps = dep2.getDynDeps();
    var moduleB = {};
    var loaded = new $.Deferred();

    require(dyndeps, function() {
        moduleB.m = function() { ... };
        loaded.resolve(moduleB);
    })

    return loaded.promise();    
});
Run Code Online (Sandbox Code Playgroud)

这种方法唯一存在的问题是客户端代码(A.js)需要知道以B特殊方式依赖.更好的解决方案是B隐藏其动态性质,如:

// A.js
define(["B"], function(moduleB){
    moduleB.m();
})

// B.js
define([ "promise!dynamicB" ], function( moduleB ) {
    return moduleB;
});

// still inside B.js define a "private" named module:
define("dynamicB", ["dep1", "dep2", "jquery"], function() {
    var dyndeps = dep2.getDynDeps();
    var loaded = new $.Deferred();
    var moduleB = {};

    require(dyndeps, function() {
        moduleB.m = function() { ... };
        loaded.resolve(moduleB);
    })

    return loaded.promise();    
});
Run Code Online (Sandbox Code Playgroud)

现在B可以像任何其他模块一样使用.