需要 JS 依赖项覆盖以实现可配置的依赖项注入

RequireJS dependency override for configurable dependency injection

本文关键字:依赖 配置 注入 JS 覆盖 需要 实现      更新时间:2023-09-26

我正在使用的东西似乎非常适合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);
            }
        }
    };
});

这与实际代码相去甚远,但重要的部分是 require 的工作原理。请注意,在注入器代码中,依赖项是必需的,并且在 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);
            }
        }
    };
});

显然,这有问题。如果在异步需求调用完成之前调用 show,则Dep1仍将为 null。所以我们并没有真正显示依赖性,这是一个目标,显然在这种情况下会抛出JS错误。此外,我们仍在使用我不喜欢的if检查节目,但用例是依赖项可能存在也可能不存在,我们只是不想在不需要时需要它,所以我可能无法绕过它。另请记住,model.showDependency实际上不是布尔值。它可以有多个值,这些值需要不同的依赖项。为了便于理解基本问题,我只是在这里将其剥离。

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

想法三使依赖项基于 model.showDependency 属性返回 null。这可能是目前最好的解决方案。我仍然坚持一些if,但我认为这不会消失。此外,这会阻止调用初始化代码。

有什么更好的主意吗?

为什么不尝试使用承诺来加载依赖项呢?

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

选项 1(为模块"view/injector"的结果返回一个承诺,这个承诺的结果将是上面显示的当前对象结果。

选项 2(使用承诺加载依赖项,然后在解决承诺后执行逻辑。

下面是选项 2 的示例,使用 jQuery 样式延迟。 我通常更喜欢当.js或 Q. 如果追加顺序很重要,此示例可能会崩溃。

// 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);
                });
            }
        }
    };
});