web-dev-qa-db-ja.com

関数で$ rootScopeを使用することが推奨されないのはなぜですか?

AngularjsのFEQを調べている間、私は以下の記事を見ました:

$ rootScopeは存在しますが、悪に使用できます

Angularのスコープは階層を形成し、通常はツリーの最上位にあるルートスコープから継承します。ほとんどのビューにはコントローラーがあり、したがって独自のスコープがあるため、通常は無視できます。 。

時折、アプリ全体に対してグローバルにしたいデータがあります。これらの場合、他のスコープと同様に、$rootScopeを挿入して値を設定できます。スコープはルートスコープから継承するため、これらの値は、ローカルのng-showの値と同じように、$scopeのようなディレクティブにアタッチされた式で使用できます。

もちろん、グローバル状態は最悪なので、任意の言語のグローバル変数で使用するのと同じように、$rootScopeは控えめに使用する必要があります。特に、コードには使用せず、データのみに使用してください。関数を$rootScopeに配置したい場合は、ほとんどの場合、必要な場所に挿入でき、より簡単にテストできるサービスに関数を配置することをお勧めします。

逆に、人生の唯一の目的がデータのビットを保存して返すことであるサービスを作成しないでください。

— AngularJS FAQ-$ rootScopeは存在しますが、悪に使用できます

では、なぜ$ rootScopeがグローバル関数としての関数に推奨されないのか疑問です。パフォーマンスの問題はありますか?

12

私は過去にこれに答えましたが、あなたがこれらの質問をしているのは良いことです。

$ rootScopeは存在しますが、Angular階層を形成し、通常はツリーの最上位にあるルートスコープから継承する悪のスコープに使用できます。ほとんどのビューには独自のコントローラー、したがってスコープ。

分離されていないスコープは階層的ですが、ほとんどの開発者は、分離されたスコープを持つディレクティブを使用する必要があります。 AngularJSのスコープの非常に階層的な性質は、angularアプリの多くバグの原因です。これは私が呼びたい問題ですスコープの出血ここでスコーププロパティはDOMツリーのどこかで魔法のように変更されており、その理由はわかりません。

Angularのdefaultの動作は固有のスコープに対するものであり、これにより、あるコントローラーが別のコントローラーによって管理されているものを更新するようになります。これは、ソースコード間のスパゲッティ接続が作成される方法です。そのコードを維持することを非常に困難にします。

時折、アプリ全体に対してグローバルにしたいデータがあります。これらの場合、他のスコープと同じように$ rootScopeを挿入し、それに値を設定できます。

いいえ、それは正しくありません。 AngularJSを使用すると、定数、値、サービスなどを定義できます。これらは、ルート、コントローラー、およびディレクティブにinjectedできるものです。これが、アプリからグローバルにアクセスできるようにする方法であり、コントローラーまたはディレクティブをテスト可能にしたい場合は、この方法で行います。単体テストの作成者は、ディレクティブまたはコントローラーが依存する$ rootScopeのプロパティを認識していません。彼らは、サービスやデータを提供するために$ rootScopeが変化していないと想定する必要があります。

もちろん、グローバル状態は最悪であり、(願わくば)任意の言語のグローバル変数で使用するのと同じように、$ rootScopeを慎重に使用する必要があります。

問題は$ rootScopeではなく、人々がそれを使って何をしているのかです。多くのアプリは、現在のユーザー、認証トークン、およびセッションデータをrootScopeに追加します。これは、テンプレートで頻繁に使用されることになります(ユーザーがログインしている場合はXを表示し、そうでない場合はYを表示します)。問題は、HTMLがスコープ階層を伝達しないことです。したがって、_{{user.firstname + ' ' + user.lastname}}_を見ると、変数userがどこから来たのかわかりません。 2番目の問題は、子スコープがルートプロパティをシャドウする可能性があることです。前の例のように、ディレクティブがこれを行う場合は_scope.user = 'bla bla bla'_。 rootScopeの値は置き換えられていません。それは隠されています。これで、テンプレートに予期しない奇妙なことがいくつか発生し、変数userが変更された理由がわかりません。

逆に、人生の唯一の目的がデータのビットを保存して返すことであるサービスを作成しないでください。

Angularの_$cacheFactory_と_$templateCache_は、データを保存しすぎるだけで存在するサービスの例です。著者はAngularのモジュールで定数と値の使用を奨励しようとしていたと思いますが、それはそれを行うための良い説明ではありません。

だから私の疑問は、なぜ$ rootScopeがグローバル関数としての関数に推奨されないのですか?パフォーマンスの問題はありますか?

$ rootScopeは、angular.config(..)中に使用できる唯一のスコープです。これが唯一の時間である場合、スコープを変更できるのはこの時間です。例えば; APIキーまたはGoogle分析変数を挿入する必要がある場合がありますbeforeアプリが起動します。

anyスコープの関数は一般的に悪い考えです。主な理由は、スコープ内のすべてがテンプレート上の式に消化されるためです。 hide重い操作にテントを張る関数。関数を呼び出すときにHTMLを読み取っても、テンプレートの重さを判断することはできません。関数自体が3レベルのネストされたループを実行するgetHeight()のようなスコープ関数を見てきました。この関数は、angularがウォッチャーをダイジェストして、変更されているかどうかを確認するたびに呼び出す必要があります。テンプレートはできるだけdryに保つようにしてください。

10
Reactgular

グローバル変数が乱用されている

$rootScopeはほとんどグローバル変数であり、その場所がありますが、それを使用するほとんどの人によって間違いなく悪用されています。これらは、グローバルが一般的に使用されるべきではない理由です。

Non-locality-ソースコードは、個々の要素の範囲が制限されている場合に最も理解しやすくなります。グローバル変数は、プログラムのどの部分でも読み取ったり変更したりできるため、考えられるすべての使用法を覚えたり、推論したりすることが困難になります。

アクセス制御または制約チェックなし-グローバル変数はプログラムの任意の部分で取得または設定でき、その使用に関するルールは簡単に設定できます壊れているか忘れられている。 (言い換えると、get/setアクセサーは一般に直接データアクセスよりも好ましく、これはグローバルデータの場合はさらにそうです。)さらに、アクセス制御の欠如は、信頼できないコードを実行したい状況でのセキュリティの達成を大きく妨げます。 (サードパーティのプラグインの操作など)。

暗黙の結合-多くのグローバル変数を持つプログラムは、多くの場合、それらの変数のいくつかの間で緊密な結合、および変数と関数の間の結合を持っています。結合されたアイテムをまとまりのあるユニットにグループ化すると、通常、より良いプログラムにつながります。

同時実行の問題-グローバルが複数の実行スレッドによってアクセスできる場合、同期が必要です(そしてあまりにもしばしば無視されます)。モジュールをグローバルと動的にリンクする場合、数十の異なるコンテキストでテストされた2つの独立したモジュールが安全であったとしても、構成されたシステムはスレッドセーフではない可能性があります。

名前空間の汚染-グローバル名はどこでも利用できます。ローカルを使用していると思われる場合(スペルを間違えたり、ローカルの宣言を忘れたりすることにより)、無意識のうちにグローバルを使用してしまう可能性があります。その逆も同様です。また、同じグローバル変数名を持つモジュールをリンクする必要がある場合、運が良ければリンクエラーが発生します。運が悪ければ、リンカは同じ名前のすべての使用を同じオブジェクトとして扱うだけです。

メモリ割り当ての問題-一部の環境には、グローバルの割り当てをトリッキーにするメモリ割り当てスキームがあります。これは、「コンストラクター」に割り当て以外の副作用がある言語で特に当てはまります(その場合、2つのグローバルが相互に依存しているという危険な状況を表現できるため)。また、モジュールを動的にリンクする場合、異なるライブラリに独自のグローバルインスタンスがあるかどうか、またはグローバルが共有されているかどうかが不明確になる可能性があります。

テストと制限-グローバルを利用するソースは、実行間で「クリーンな」環境を簡単にセットアップできないため、テストがやや困難です。より一般的には、そのソースに明示的に提供されていないあらゆる種類のグローバルサービス(ファイルやデータベースの読み取りと書き込みなど)を利用するソースは、同じ理由でテストが困難です。通信システムの場合、システムの不変条件をテストするには、システムの複数の「コピー」を同時に実行する必要があります。これは、テストの一部として共有するために提供されていない共有サービス(グローバルメモリを含む)の使用によって大幅に妨げられます。 。

ソースhttp://c2.com/cgi/wiki?GlobalVariablesAreBad

Angularでデータを共有する

Angularのコントローラー間でデータを共有する場合は、サービスを使用する必要があります。カスタムサービスを使用すると、getterメソッドとsetterメソッドを作成できます。必要なコントローラーにデータを挿入できます。アプリで使用してください。

3
Joe Lloyd

パフォーマンスの問題はありません。多くのサービスを依存性注入する必要がないため、実際には時間の一部だけパフォーマンスが向上します。

しかし、それは設計の大きな懸念事項です。大規模なアプリケーションを検討してください。数十から数十のビュー、複雑なコンポーネントがあり、よく知られているAPIの数(Twitter、Flickr、Facebook、OAuthなど)。

このアプリケーションを単独で開発することはありません。次の問題が発生します。

名前空間

あなたはFacebookAPIに取り組んでおり、他の誰かがTwitterAPIに取り組んでいます。関数に_$rootScope_を使用することは良い考えであり、どちらも_$rootScope.login_関数を作成すると考えています。 _git merge_を実行するときに、これをどのように解決しますか?名前空間が必要です。残念ながら、2つのサービスmyFacebookAPImyTwitterAPIを開発する必要があります。これらのサービスは、ログイン用に同じインターフェイスを実装できます(login(user,pw))。これにより、次のようなことができる場合に、コントローラーで処理している実際のソーシャルネットワークを抽象化できることに注意してください。

_$scope.callAction = function (action) {
var service;
    if ($scope.serviceSelected === 'fb') {
         service = myFacebookAPI;
    } else {
         service = myTwitterAPI;
    }
    service[action]();
};
_

テスト

専門的に開発するときは、テストを作成します。 Angularは、サービスなどの自動テストを実行するためのツールを提供しますが、_$rootScope_に割り当てたものを同じ快適な方法でテストすることはできません。

他の問題も発生しますが、自分で考えれば十分だと思います。

1
Kevin Dreßler