35

Promises を使用して、AngularJS で静的リソースの動的読み込みを実装したいと考えています。問題: サーバーから静的リソースを取得する必要がある可能性がある (または表示されているかどうかに応じて動的である) ページにいくつかのコンポーネントがあります。ロードされると、アプリケーションの存続期間全体にわたってキャッシュできます。

私はこのメカニズムを実装しましたが、Angular と Promises は初めてなので、これが適切なソリューション \ アプローチであるかどうかを確認したいと考えています。

var data = null;
var deferredLoadData = null;

function loadDataPromise() {
  if (deferredLoadData !== null)
    return deferredLoadData.promise;

  deferredLoadData = $q.defer();

  $http.get("data.json").then(function (res) {
    data = res.data;
    return deferredLoadData.resolve();
  }, function (res) {
    return deferredLoadData.reject();
  });

  return deferredLoadData.promise;
}

したがって、リクエストは 1 つだけ行われ、loadDataPromise() への次の呼び出しはすべて、最初に行われた promise を取得します。進行中のリクエストや、しばらく前に終了したリクエストに対応しているようです。

しかし、Promise をキャッシュするのは良い解決策でしょうか?

4

3 に答える 3

48

これは正しいアプローチですか?

はい。返す関数でメモ化を使用すると、非同期の (そして通常は高価な) タスクの繰り返し実行を回避するための一般的な手法が約束されます。進行中の操作と完了した操作を区別する必要がなく、どちらも結果値の (同じ) promise として表されるため、promise によりキャッシングが容易になります。

これは正しい解決策ですか?

いいえ。そのグローバルdata変数と解決策undefinedは、約束がどのように機能することを意図したものではありません。代わりに、結果で約束を果たしdataます! また、コーディングがはるかに簡単になります。

var dataPromise = null;

function getData() {
    if (dataPromise == null)
        dataPromise = $http.get("data.json").then(function (res) {
           return res.data;
        });
    return dataPromise;
}

次に、代わりにloadDataPromise().then(function() { /* use global */ data })単にgetData().then(function(data) { … }).

パターンをさらに改善するには、クロージャー スコープに非表示にすることをお勧めします。パラメーター (URL など) をdataPromise受け取るときに、さまざまなプロミスのルックアップが必要になることに注意してください。getData

于 2013-09-11T15:35:51.767 に答える
3

このタスクのために、この定型コードをすべて削除する defer-cache-service というサービスを作成しました。Typescript で書かれていますが、コンパイルされた js ファイルを取得できます。Github ソースコード.

例:

function loadCached() {
   return deferCacheService.getDeferred('cacke.key1', function () {
      return $http.get("data.json");
   }); 
} 

そして消費する

loadCached().then(function(data) {
//...
});

2 つ以上の部分が同じ loadDataPromise を同時に呼び出している場合、このチェックを追加する必要があることに注意してください。

if (defer && defer.promise.$$state.status === 0) {
   return defer.promise;
}

そうしないと、バックエンドに対して重複した呼び出しを行うことになります。

于 2015-11-30T14:36:30.517 に答える