返す前にangularjsの約束を解決できますか?


125

プロミスを返す関数を書こうとしています。ただし、要求された情報がすぐに利用できる場合があります。私はそれを約束に包んで、消費者が決定をする必要がないようにしたいと思います。

function getSomething(id) {
    if (Cache[id]) {
        var deferred = $q.defer();
        deferred.resolve(Cache[id]); // <-- Can I do this?
        return deferred.promise;
    } else {
        return $http.get('/someUrl', {id:id});
    }
}

次のように使用します。

somethingService.getSomething(5).then(function(thing) {
    alert(thing);
});

問題は、コールバックが事前に解決されたpromiseに対して実行されないことです。これは正当なことですか?この状況を処理するより良い方法はありますか?


10
最初のケースでリターンを記述するより簡単な方法は、ですreturn $q.when(Cache[id])。とにかく、毎回新しいプロミスを作成しているので、これは機能し、毎回コールバックを呼び出す必要があります。
musically_ut


1
クラッド。私の人生の1時間が失われました。私はこれを単体テストで試していましたが、テストが完了した後、約束は満たされましたが、見ていませんでした。コードではなく、テストに問題があります。
Craig Celeste

$ scope。$ apply()を呼び出して、テスト中に問題がすぐに解決することを確認してください。
dtabuenc 2013

私はhttpbackend.flushがこれを説明すると思いますが、$ qはそうではないかもしれません。このテストではスコープを使用していません。私はサービスを直接テストしていますが、とにかくそれを機能させました。
Craig Celeste

回答:


174

短い答え:はい、 AngularJSのプロミスを解決してから返すことができ、期待どおりに動作します。

JB NizetのPlunkrからですが、最初に要求された内容(つまり、サービスへの関数呼び出し)のコンテキスト内で実際にサイトで機能するようにリファクタリングされています。

サービス内...

function getSomething(id) {
    // There will always be a promise so always declare it.
    var deferred = $q.defer();
    if (Cache[id]) {
        // Resolve the deferred $q object before returning the promise
        deferred.resolve(Cache[id]); 
        return deferred.promise;
    } 
    // else- not in cache 
    $http.get('/someUrl', {id:id}).success(function(data){
        // Store your data or what ever.... 
        // Then resolve
        deferred.resolve(data);               
    }).error(function(data, status, headers, config) {
        deferred.reject("Error: request returned status " + status); 
    });
    return deferred.promise;

}

コントローラーの中...

somethingService.getSomething(5).then(    
    function(thing) {     // On success
        alert(thing);
    },
    function(message) {   // On failure
        alert(message);
    }
);

誰かのお役に立てば幸いです。他の答えははっきりしていません。


2
私がどれほど幸せなイムであるかを言葉で説明することはできません。
rilar 2014

http GETが失敗した場合、返されたpromiseはこの方法で拒否されません。
lex82、2014年

5
したがって、この投稿のtl; drは次のとおりです。はい、プロミスを解決してから返すことができ、意図したとおりにショートします。
光線

1
この回答は、Angularの約束が基づくKris KowalのQにも適用されます。
キース

私はあなたの答えにエラー処理の例を追加しました。
Simon East

98

Angular 1.xで解決済みのプロミスを単純に返す方法

解決済みの約束:

return $q.when( someValue );    // angular 1.2+
return $q.resolve( someValue ); // angular 1.4+, alias to `when` to match ES6

拒否された約束:

return $q.reject( someValue );

1
そのファクトリーは必要ありません。これらのヘルパー関数はすでに利用可能です:{resolved: $q.when, rejected: $q.reject}
Bergi

ベルギさん、貴重な貢献に感謝します。私はそれに応じて私の答えを編集しました。
Andrey Mikhaylov-lolmaus 2015

2
この答えを選択すべきだと思います。
Morteza Tourani 2016年

@mortezaT選択された場合、ゴールデンバッジは得られません。;)
Andrey Mikhaylov-lolmaus 2016年

6

実際にデータを配列またはオブジェクトにキャッシュしたい場合、通常は次のようにします

app.factory('DataService', function($q, $http) {
  var cache = {};
  var service= {       
    getData: function(id, callback) {
      var deffered = $q.defer();
      if (cache[id]) {         
        deffered.resolve(cache[id])
      } else {            
        $http.get('data.json').then(function(res) {
          cache[id] = res.data;              
          deffered.resolve(cache[id])
        })
      }
      return deffered.promise.then(callback)
    }
  }

  return service

})

DEMO


0

キャッシュ要素を初期化するのを忘れました

function getSomething(id) {
    if (Cache[id]) {
        var deferred = $q.defer();
        deferred.resolve(Cache[id]); // <-- Can I do this?
        return deferred.promise;
    } else {
        Cache[id] = $http.get('/someUrl', {id:id});
        return Cache[id];
    }
}

ごめんなさい。それは本当だ。私は質問を明確にするためにコードを簡略化しようとしました。それでも、事前に解決されたpromiseに入る場合、コールバックを呼び出していないようです。
Craig Celeste

2
あなたがプロミスでプロミスを解決すると、内側のプロミスはフラット化されるとは思いません。これによりCache、オブジェクトがキャッシュにある場合とそうでない場合に、意図したオブジェクトではなくpromiseと戻り値の型が設定されます。これはもっと正しいと思います:$http.get('/someUrl', {id: id}).then(function (response) { Cache[id] = response.data; return Cache[id]; });
musically_ut

0

ファクトリーを使用して、リソースからデータを取得するのが好きです。

.factory("SweetFactory", [ "$http", "$q", "$resource", function( $http, $q, $resource ) {
    return $resource("/sweet/app", {}, {
        "put": {
            method: "PUT",
            isArray: false
        },"get": {
            method: "GET",
            isArray: false
        }
    });
}]);

次に、このようなサービスでモデルをここに公開します

 .service("SweetService",  [ "$q", "$filter",  "$log", "SweetFactory",
    function ($q, $filter, $log, SweetFactory) {

        var service = this;

        //Object that may be exposed by a controller if desired update using get and put methods provided
        service.stuff={
            //all kinds of stuff
        };

        service.listOfStuff = [
            {value:"", text:"Please Select"},
            {value:"stuff", text:"stuff"}];

        service.getStuff = function () {

            var deferred = $q.defer();

          var promise = SweetFactory.get().$promise.then(
                function (response) {
                    if (response.response.result.code !== "COOL_BABY") {
                        deferred.reject(response);
                    } else {
                        deferred.resolve(response);
                        console.log("stuff is got", service.alerts);
                        return deferred.promise;
                    }

                }
            ).catch(
                function (error) {
                    deferred.reject(error);
                    console.log("failed to get stuff");
                }
            );

            promise.then(function(response){
                //...do some stuff to sett your stuff maybe fancy it up
                service.stuff.formattedStuff = $filter('stuffFormatter')(service.stuff);

            });


            return service.stuff;
        };


        service.putStuff = function () {
            console.log("putting stuff eh", service.stuff);

            //maybe do stuff to your stuff

            AlertsFactory.put(service.stuff).$promise.then(function (response) {
                console.log("yep yep", response.response.code);
                service.getStuff();
            }).catch(function (errorData) {
                alert("Failed to update stuff" + errorData.response.code);
            });

        };

    }]);

次に、コントローラーはそれを組み込んで公開するか、注入されたServiceを参照するだけで、そのコンテキストで正しいことを実行できます。

大丈夫と思われる。でも、私はちょっとアンギュラーです。*エラー処理は明確にするためにほとんど省略されています


あなたのgetStuff方法は据え置きアンチパターン
Bergi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.