6

今日、構成またはプロバイダーに注入されることは、サービス、ファクトリ、またはコントローラーに注入されること$injectorとは異なることがわかりました。$injector

そしてget()、この $injectors の機能は異なる動作をします。

$injector構成またはプロバイダーから、get()どのサービスもできません! $injector.get('myService')をスローError: [$injector:unpr] Unknown provider: myServiceしますが、$injector.has('myService')true を返します。それは非常に奇妙です。

$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();
                }
            }

        });

ここにプレイするプランカーがあります

2つの異なるインジェクターがある理由を誰か説明できますか?

そして、プロバイダー/構成から $injector を使用してサービスを注入するにはどうすればよいですか (もちろん、サービスが初期化された後)?

PS私はAngular 1.3.13を使用しています

4

3 に答える 3

8

github でこの問題を見つけました: https://github.com/angular/angular.js/issues/5559

config 関数では、$injector はプロバイダーインジェクターであり、run 関数では、$injector はインスタンスインジェクターです。

1 つは構成段階の $injector (プロバイダーと定数のみアクセス可能) で、もう 1 つは実行段階の $injector です。混乱は、 $injector が構成から実行へと一線を越えるときに新しいものを含めるようにそれ自体を変更すると考えているかもしれませんが、それは真実ではありません。これらは 2 つの別個の (関連はありますが) オブジェクトであり、それぞれにインスタンスのキャッシュがあります。

この二分法のより詳細な理由は、おそらく $injector の内部構造の深い学習に由来するでしょう。インスタンスキャッシュの「キャッシュミス」に対処します。

v2 でインジェクターをオーバーホールする予定なので、そこで修正されます (config フェーズを取り除くことは、インジェクター v2 の目的の 1 つです)。

実際には 2 つの異なるインジェクターがあり、Angular 開発者はその動作を修正しません (バージョン <2.0)。そして、なんらかの理由で $injector ドキュメントにその側面に関するメモを誰も追加しませんでした。

ハックなトリックなしに、構成ブロック内でインスタンスインジェクターを実際に取得する方法を見つけることができませんでした。そこで、そのような問題を解決するためにかわいいプロバイダーを書きます。

.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){}])
于 2015-04-29T03:25:53.913 に答える
1

Ok。あなたのコメントを読んだ後、これが私の答えです。

providerInjector.get() を呼び出すとき、コードは次のようになります。

$scope.getMyServiceFromProviderInjector = function () {
        try {
                 myProvider.providerInjector.get('myServiceProvider');//here is change in provider name
                 return "OK";
            } catch (e) {
                 return e.toString();
            }
   };

angular docsによると、構成および実行ブロックについては以下が引用されています。

  • 構成ブロック - プロバイダーの登録および構成フェーズ中に実行されます。構成ブロックに挿入できるのは、プロバイダーと定数のみです。これは、サービスが完全に設定される前に、サービスが偶発的にインスタンス化されるのを防ぐためです。
  • 実行ブロック - インジェクターが作成された後に実行され、アプリケーションのキックスタートに使用されます。実行ブロックに挿入できるのは、インスタンスと定数のみです。これは、アプリケーションの実行時にさらにシステムが構成されないようにするためです。

これは単純に、構成ブロック内でサービスのインスタンスを取得できないことを意味します。

于 2015-04-28T08:22:12.123 に答える