web-dev-qa-db-ja.com

$ q promiseエラーコールバックチェーン

次のコードスニペットerror 1およびsuccess 2がログに記録されます。元の遅延オブジェクトが拒否された場合に呼び出される成功コールバックではなく、呼び出されるエラーコールバックを伝播するにはどうすればよいですか。

angular.module("Foo", []);
angular
.module("Foo")
.controller("Bar", function ($q) {
    var deferred = $q.defer();
      deferred.reject();

      deferred.promise
          .then(
              /*success*/function () { console.log("success 1"); },
              /*error*/function () { console.log("error 1"); })
          .then(
              /*success*/function () { console.log("success 2"); },
              /*error*/function () { console.log("error 2"); });
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="Foo">
    <div ng-controller="Bar"></div>
</div>
25
Steven Wexler

エラーは、エラーコールバックで$q.rejectを返すことで伝播します

    var deferred = $q.defer();
      deferred.reject();

      deferred.promise
          .then(
              /*success*/function () { console.log("success 1"); },
              /*error*/function () { console.log("error 1"); return $q.reject('error 1')})
          .then(
              /*success*/function () { console.log("success 2"); },
              /*error*/function () { console.log("error 2"); });
});
31
Chandermani

成功/失敗をトライ/キャッチと考える

_try{
    var val = dummyPromise();
} catch (e){
    val = "SomeValue";
}
_

catchが例外をスローしない場合、エラーが処理されたと見なされるため、外部呼び出し関数は内部関数で発生したエラーを認識しません。

ここでも同様のことが起こります。チェーンの次のプロミスが失敗するためには、プロミスからreturn $q.reject();を返す必要があります。 plunkerの例を参照してください: http://plnkr.co/edit/porOG8qVg2GkeddzVHu3?p=preview

理由は次のとおりです。エラーハンドラーがエラーを訂正するアクションを実行する場合があります。エラー関数では、エラーに対処する場合、特に指定がない限り、解決された新しいプロミスを返します。したがって、デフォルトで次のプロミスが失敗するのは妥当ではありません(try-catchのアナロジー)。

ちなみに、successハンドラからでも、エラー状態を感知して$q.reject()を返すと、次の約束が得られますチェーンの失敗。エラーをキャッチして処理しているので、成功ハンドラに到達します。拒否したい場合は、$ q.reject();を返すことで拒否する必要があります。

15
harishr

コメントを要約して、promiseチェーンでエラーを伝播するには、次のいずれかを行います。

1)errorCallbackthenを指定しないでください:

_deferred.promise
.then(
  /*success*/function () { console.log("success 1"); },
.then(
  /*success*/function () { console.log("success 2"); },
  /*error*/function () { console.log("error 2"); }); // gets called
_

または

2)errorCallbackから$q.reject()を返します。

_deferred.promise
.then(
  /*success*/function () { console.log("success 1"); },
  /*error*/function (err) { console.log("error 1"); return $q.reject(err); });
.then(
  /*success*/function () { console.log("success 2"); },
  /*error*/function () { console.log("error 2"); }); // gets called
_

angular $ q.reject documentation から:

_This api should be used to forward rejection in a chain of promises.
_
6
user1338062