RequireJS依赖关系覆盖可配置依赖项注入

时间:2013-09-29 21:56:43

标签: javascript dependency-injection

我正在使用一些看起来非常适合DI的东西,但它被添加到现有的框架中,在编写时没有考虑到这一点。定义依赖关系的配置来自后端模型。实际上它不是一个完整的配置,它基本上包含一个可用于确定特定视图是否可用的密钥。

我正在使用require,因此依赖关系看起来像这样

// Dependency
define(['./otherdependencies'], function(Others) {
    return {
        dep: "I'm a dependency"
    };
});

现在注射器看起来像这样

// view/injector
define([
    './abackendmodel',
    './dependency'
], function(Model, Dependency) {
    return {
        show: function() {
            if (model.showDepency) {
                var dep = new Dependency();
                this.$el.append(dep);
            }
        }
    };
});

这与实际代码相差甚远,但重要的部分是需要如何工作。请注意,在进样器代码中,依赖关系是必需的,并且在show方法中使用,但仅在模型显示应该显示时才使用。问题是依赖关系可能需要额外的东西,当它不应该显示时不可用。所以我真正想做的是除非model.showDependency为真,否则不必指定依赖关系。我想出了几个想法,但没有我喜欢的。

创意 根据该模型属性进行另一个异步需要调用。所以注射器看起来像这样。

// Idea 2 view/injector
define([
    './abackendmodel'
], function(Model) {
    var Dep1 = null;
    if (model.showDepedency) {
        require([
            './dependency'
        ], function(Dependency) {
            Dep1 = Dependency;
        });
    }
    return {
        show: function() {
            if (Dep1) {
                var dep = new Dep1();
                this.$el.append(dep);
            }
        }
    };
});

显然这有问题。如果在async require调用完成之前调用show,则Dep1仍将为null。所以我们并没有真正展示作为目标的依赖关系,显然在这种情况下会抛出JS错误。此外,我们仍然使用if显示我不喜欢的节目,但用例是依赖可能存在或不存在,如果不需要,我们只是不想要它我可能无法解决这个问题。另请注意,model.showDependency实际上不是布尔值。它可以有多个值,这些值将要求不同的依赖项。我只是为了简化理解基本问题而在这里剥离它。

想法二 这不太固化,即我认为这甚至不会起作用,但我考虑过使用require config.path的东西。我的想法基本上有两个配置,以便'./dependency'指向不同的地方。问题是尽管model.showDependency值是配置是相同的需要配置,因此无法在运行时更改它。也许有一些魔法可以在这里完成,比如定义单独的视图目录路径并使用工厂类型对象返回我们关心的那个,但是因为这最终将导致 Idea one 我认为没有给我买任何东西(它基本相同)。

想法三 让依赖项在model.showDependency属性上返回null。 这可能是目前最好的解决方案。我仍然坚持一些if但我不认为这会消失。这也防止了初始化代码被调用。

有更好的想法吗?

1 个答案:

答案 0 :(得分:1)

为什么不尝试使用promise来加载依赖项?

您有两种选择,具体取决于代码的工作方式。

选项1) 返回模块'view / injector'结果的promise,这个promise的结果将是上面显示的当前对象结果。

选项2) 使用promise来加载依赖项,然后在promise被解析后执行逻辑。

以下是选项2的示例,使用延迟的jQuery样式。我通常更喜欢 when.jsQ。如果附加顺序很重要,此示例可能会分崩离析。

// Option 2
define([
    './abackendmodel'
], function(Model) {
    var dep1Promise = null;
    if (model.showDepedency) {
        var dep1Deferred = $.Deferred();
        dep1Promise = dep1Deferred.promise();

        require([
            './dependency'
        ], function(Dependency) {
            dep1Deferred.resolve(Dependency);
        }, dep1Deferred.reject); // Optionally reject the promise if there is an error finding the dependency.

    }
    return {
        show: function() {
            if (dep1Promise) {
                dep1Promise.then(function(Dep1) { 
                    var dep = new Dep1();
                    this.$el.append(dep);
                });
            }
        }
    };
});