32

angular では、サービスを介してアプリケーション全体に公開されるオブジェクトがあります。

そのオブジェクトのフィールドの一部は動的であり、サービスを使用するコントローラーのバインディングによって通常どおり更新されます。ただし、一部のフィールドは計算されたプロパティであり、他のフィールドに依存し、動的に更新する必要があります。

簡単な例を次に示します (これは jsbin hereで動作しています)。私のサービス モデルは fieldsaを公開bし、cwherecは in から計算さa + BcalcC()ます。私の実際のアプリケーションでは、計算はもっと複雑ですが、本質はここにあります。

これを機能させるために考えられる唯一の方法は、サービス モデルを にバインドし、$rootScopeを使用$rootScope.$watchして、コントローラーの変更を監視するか、コントローラーが変更さabたときに を再計算することですc。しかし、それは醜いようです。これを行うより良い方法はありますか?


2 つ目の懸念事項は、パフォーマンスです。私の完全なアプリケーションabは、 と は、 に集約されるオブジェクトの大きなリストですc。これは、$rootScope.$watch関数が多くの深い配列チェックを行うことを意味し、パフォーマンスが低下するように聞こえます。

私はこれをBackBoneのイベント化されたアプローチですべて機能させています。これにより、再計算が可能な限り削減されますが、角度はイベント化されたアプローチではうまく機能しないようです。それについての考えも素晴らしいでしょう。


これがアプリケーションの例です。

var myModule = angular.module('myModule', []);

//A service providing a model available to multiple controllers
myModule.factory('aModel', function($rootScope) {
  var myModel = {
    a: 10,
    b: 10,
    c: null
  };

  //compute c from a and b
  calcC = function() {
    myModel.c = parseInt(myModel.a, 10) * parseInt(myModel.b, 10);
  };

  $rootScope.myModel = myModel;
  $rootScope.$watch('myModel.a', calcC);
  $rootScope.$watch('myModel.b', calcC);

  return myModel;
});


myModule.controller('oneCtrl', function($scope, aModel) {
  $scope.aModel = aModel;
});

myModule.controller('twoCtrl', function($scope, aModel) {
  $scope.anotherModel = aModel;
});
4

5 に答える 5

7

大まかに言えば、bmleite の回答に同意します ($rootScope を使用するために存在し、$watch を使用するとユースケースで機能するようです)、別のアプローチを提案したいと思います。

値を再計算する変更をリスナー$rootScope.$broadcastにプッシュするために使用します。$rootScope.$onc

これは、手動で行うことができます。つまり、aまたはb値を積極的に変更する場合、または更新の頻度を抑えるために短いタイムアウトで行うこともできます。それからさらに一歩進んで、サービスに「ダーティ」フラグを作成し、c必要な場合にのみ計算されるようにします。

a明らかに、このようなアプローチは、コントローラーやディレクティブなどの再計算により多くの関与を意味しますが、更新をorのすべての可能な変更にバインドしたくない場合b、問題は「どこに線を引くか」の問題になります。

于 2013-02-18T21:57:18.980 に答える
4

あなたの質問を読んであなたの例を初めて見たとき、「これは間違っている」と思ったのですが、もう一度調べてみると、思ったほど悪くないことに気づきました。

アプリケーション全体で何か$rootScopeを共有したい場合は、それを置くのに最適な場所です。もちろん、注意が必要です。これはすべてのスコープ間で共有されるものであるため、誤って変更したくないでしょう。しかし、それは本当の問題ではありません。ネストされたコントローラー (子スコープは親スコープのプロパティを継承するため) と分離されていないスコープ ディレクティブを使用する場合は、すでに注意が必要です。「問題」はすでにそこにあり、このアプローチに従わない言い訳としてそれを使用すべきではありません。

を使う$watchのも良さそうです。これは、フレームワークが既に無料で提供しているものであり、必要なことを正確に実行します。では、なぜ車輪を再発明するのでしょうか? アイデアは、基本的に「変更」イベント アプローチと同じです。

パフォーマンス レベルでは、アプローチは実際には「重い」場合がありますが、aおよびbプロパティを更新する頻度に常に依存します。たとえば、(jsbin の例のように)入力ボックスのaorbを設定 すると、ユーザーが何かを入力するたびに再計算されます...これは明らかに過剰処理です。ソフトなアプローチを使用し、必要に応じてのみ更新および/または更新する場合、パフォーマンスの問題は発生しないはずです。「変更」イベントまたはセッターとゲッターのアプローチを使用して再計算するのと同じです。ただし、本当にリアルタイムで再計算する必要がある場合(つまり:ng-modelcabcc$rootScope$watchそれはそれを改善するのに役立ちます。

繰り返しますが、私の意見では、あなたのアプローチは(まったく!)悪くありません。$rootScopeプロパティに注意し、「リアルタイム」処理を避けてください。

于 2013-01-29T16:11:26.917 に答える
2

一般的に、これはおそらく良い考えではありません。また、リファクタリングがより困難で面倒になる以外の理由がない場合は、モデルの実装をすべての呼び出し元に公開することも(一般的に)悪い習慣です。両方を簡単に解決できます。

myModule.factory( 'aModel', function () {
  var myModel = { a: 10, b: 10 };

  return {
    get_a: function () { return myModel.a; },
    get_b: function () { return myModel.a; },
    get_c: function () { return myModel.a + myModel.b; }
  };
});

これがベストプラクティスのアプローチです。それはうまくスケーリングし、必要なときにだけ呼び出され、汚染しません$rootScope

PS :;を呼び出すたびに再計算を回避するように、またはが設定されているc場合は更新することもできます。どちらが最適かは、実装の詳細によって異なります。abget_c

于 2013-01-29T00:54:40.603 に答える
1

あなたの構造から私が見ることができることから、ゲッターとしてaandを持つbことは良い考えではないかもしれませんがc、関数であるべきです...

だから私は提案することができます

myModule.factory( 'aModel', function () {
  return {
    a: 10,
    b: 10,
    c: function () { return this.a + this.b; }
  };
});

このアプローチでは、もちろん、入力変数に双方向バインドすることはできませんc。しかし、双方向バインディングcは意味がありcませab

于 2013-01-29T09:48:13.820 に答える