AngularJS有两个不同的$ injectors

Har*_*rns 6 dependency-injection angularjs angularjs-injector

今天我发现,$injector注入配置或提供商不同于$injector注入服务,工厂或控制器.

get()从这个$喷射功能的工作方式不同.

$injector从配置或提供商,不能get()任何服务!$injector.get('myService')抛出Error: [$injector:unpr] Unknown provider: myService,但$injector.has('myService')返回真实.这非常奇怪.

$injector 从服务或控制器正常工作.

以下是一个代码示例,以便更好地理解:

angular.module('app', [])

        .provider('myProvider', function ($injector) {
            this.$get = ['$injector', function (serviceInjector) {
                return {
                    providerInjector: $injector,
                    serviceInjector: serviceInjector
                };
            }];
        })

        .service('myService', function () {})

        .controller('myCtrl', function ($scope, myProvider) {
            var providerInjector = myProvider.providerInjector;
            var serviceInjector = myProvider.serviceInjector;

            console.log(providerInjector === serviceInjector); // -> false

            console.log(serviceInjector.has('myService')); // `serviceInjector` has `myService`
            console.log(getMyService(serviceInjector)); // `serviceInjector` can get `myService`

            console.log(providerInjector.has('myService')); // `providerInjector` has `myService` too!
            console.log(getMyService(providerInjector)); // but `providerInjector` can't get `myService`! =(

            function getMyService(injector) {
                try {
                    injector.get('myService');
                    return "OK";
                } catch (e) {
                    return e.toString();
                }
            }

        });
Run Code Online (Sandbox Code Playgroud)

这是一个可以玩的玩家

谁能解释为什么有两种不同的注射器?

如何从provider/config使用$ injector注入服务(当然,在服务初始化之后)?

PS我使用角1.3.13

Har*_*rns 8

我在github上发现了这个问题:https://github.com/angular/angular.js/issues/5559

在config函数中,$ injector是提供者注入器,其中在run函数中,$ injector是实例注入器.

一个是配置阶段的$ inject(只有提供者和常量可访问),一个是运行阶段的$ injector.混淆可能是你认为$ injector修改自己以包含新的东西,因为它跨越从配置到运行的线,但事实并非如此.它们是两个独立的(尽管是相关的)对象,具有自己的实例缓存.

这种二分法的一个更深层次的原因可能来自于对喷油器内部结构的深入了解,但它看起来像是DRY-ed相当硬核,而且两种类型的喷射器几乎都有相同的行为,除了如何他们在实例缓存中处理"缓存未命中".

我们将在v2中对喷油器进行大修,因此将在那里得到修复(摆脱配置阶段是喷油器v2的目标之一).

看起来确实有两种不同的注入器,角度开发人员不会修复这种行为(版本<2.0).由于某种原因,没有人在$ injector文档中添加关于该方面的注释.

我无法找到一种方法如何在没有hacky技巧的情况下在配置块中真正获得实例注入器.所以,我写了一个可爱的提供者来解决这类问题.

.provider('instanceInjector', function () {

    var instanceInjector;

    function get() {
        return instanceInjector;
    }

    function exists() {
        return !!instanceInjector;
    }

    angular.extend(this, {
        get: get,
        exists: exists
    });

    this.$get = function ($injector) {
        instanceInjector = $injector;

        return {
            get: get,
            exists: exists
        };
    }
})

// We need to inject service somewhere.
// Otherwise $get function will be never executed
.run(['instanceInjector', function(instanceInjector){}])
Run Code Online (Sandbox Code Playgroud)