3

私は複雑な angularjs アプリに取り組んでいます。複雑な意味での単一ビューは、コードのさまざまな場所 (ページ パーツ コントローラーやディレクティブ コントローラーなど) からクエリされる複数の異なるデータ ソースを持つことができます。これらのリクエストの一部は、解決に時間がかかる場合があり、ビューがやや無効な状態のままになることがあります。ある種の「データ読み込み」バナーを表示し、すべての約束が解決されるまでビューとのユーザー操作を無効にしたいと考えています。これは、$q.all() 関数を使用して単純な画面で機能します。ただし、アプリが構造化される方法は、データ ソース中心ではなく、よりビジネス ロジック中心です。したがって、より複雑な画面の場合、すべての約束が自然にアクセスできる単一の場所はありません。コード内にそのような場所を作成するのは面倒に思えます。

私はこの解決策を思いつきました:

angular.module('myApp').service('qConfigurer', function ($q) {
    var pending = 0;
    var origDefer = $q.defer;

    $q.defer = function() {
        pending++;
        var result = origDefer.apply(arguments);

        var origResolve = result.resolve;
        var origReject = result.reject;

        result.resolve = function() {
            pending--;
            return origResolve.apply(arguments);
        };

        result.reject = function() {
            pending--;
            return origReject.apply(arguments);
        };

        return result;
    };

    $q.pending = function() {
        return pending;
    };

    return {};
});

同じことを達成するためのハッキーは少ないですか?

4

1 に答える 1

3

あなたがしているのは、グローバルな状態を変更し$q、変更をハッキングすることです。この種の AOP は、サードパーティ モジュール プラグインで問題を簡単に作成できます。危険だと思います。変更内容を自分でスコープすることはできません。言うまでもありませんスピードペナルティ。

私が良いと思うもの

私の意見では、try(resource)Java、using(C#、またはwithPython からリソース管理を行う方法が本当に必要です。残念ながら、これを持つ唯一の promise 実装は Bluebird です。ここでは $q を使用しているので、作成してみましょう :)

したがって、Promise をスコープとする関数が必要であり、結果がどうなるかに関係なく、カウンターから 1 つを減らします。この場合、リソースはsemaphoreを形成します。

function loading(fn){  // takes a function that returns a promise, put in a service
      var args = Array.prototype.slice.call(arguments,1);
      return $q.when().then(function(){
          loading.counter++; // signal the scope somehow, either by having the counter
                             // on the scope and accepting it as a param, by a watcher or
                             // with an emit
      }).then(function(){
          return fn.apply(null, args); // can add context param if you want for `this`
      }).finally(function(){
          loading.counter--; // signal just like with the above
      });
}
loading.counter = 0;

次に、使用法は次のようになります。

 // you can use it like this
 loading(function(){
     return myService.apiCall(...);
 }).then(function(result){
      $scope.a = result;
 });
 // or like this
 loading(myService.apiCall,...).then(function(result){
     $scope.b = result;
 });

表示/非表示ロジック、イベント フック、スコープ変数、または入力パラメーターを読み込み関数に配置する場合 (これは個人的な好みのために残しておきます。値が0 に達したときと 1 に達したときに何かを実行するだけです) - ローディング画面を表示/非表示にします。

于 2014-05-19T07:57:38.037 に答える