1. ホーム
  2. javascript

[解決済み] 約束の連鎖を切断し、切断された連鎖のステップに応じた関数を呼び出す(拒否)

2022-06-26 02:47:51

質問

更新しました。

この投稿を将来見る人のために、私は このデモは、plumaの回答 .

質問です。

私の目標はかなり簡単なようです。

  step(1)
  .then(function() {
    return step(2);
  }, function() {
    stepError(1);
    return $q.reject();
  })
  .then(function() {

  }, function() {
    stepError(2);
  });

  function step(n) {
    var deferred = $q.defer();
    //fail on step 1
    (n === 1) ? deferred.reject() : deferred.resolve();
    return deferred.promise;
  }
  function stepError(n) {
    console.log(n); 
  }

ここで問題なのは、もしステップ1で失敗した場合、両方の stepError(1)stepError(2) が発射されます。もし私が return $q.reject とすると stepError(2) は解雇されませんが step(2) は解雇されるでしょう、それは理解できます。自分がやろうとしていること以外はすべて達成した。

エラーチェーンのすべての関数を呼び出すことなく、拒絶時に関数を呼び出すことができるように、どのようにプロミスを書けばよいのでしょうか?あるいは、これを達成するための別の方法がありますか?

ライブデモはこちら をご覧ください。

更新しました。

I 種類 が解決しました。ここでは、チェーンの末尾でエラーをキャッチし、そのデータを reject(data) にデータを渡して、エラー関数でどのような問題を処理すべきかを知ることができるようにしています。私はデータに依存したくないので、これは実際には私の要件を満たしていません。ダサいですが、私の場合、返されたデータに依存して何をすべきかを決定するよりも、エラー コールバックを関数に渡す方がすっきりします。

ライブデモはこちら(クリック)。

step(1)
  .then(function() {
    return step(2);
  })
  .then(function() {
    return step(3);
  })
  .then(false, 
    function(x) {
      stepError(x);
    }
  );
  function step(n) {
    console.log('Step '+n);
    var deferred = $q.defer();
    (n === 1) ? deferred.reject(n) : deferred.resolve(n);
    return deferred.promise;
  }
  function stepError(n) {
    console.log('Error '+n); 
  }

どのように解決するのですか?

あなたのコードが期待通りに動かない理由は、あなたが考えていることとは異なることを実際に行っているからです。

次のようなものがあるとします。

stepOne()
.then(stepTwo, handleErrorOne)
.then(stepThree, handleErrorTwo)
.then(null, handleErrorThree);

何が起こっているかをよりよく理解するために、これが同期コードであると仮定して try / catch のブロックがあります。

try {
    try {
        try {
            var a = stepOne();
        } catch(e1) {
            a = handleErrorOne(e1);
        }
        var b = stepTwo(a);
    } catch(e2) {
        b = handleErrorTwo(e2);
    }
    var c = stepThree(b);
} catch(e3) {
    c = handleErrorThree(e3);
}

onRejected ハンドラ(の第二引数 then のような) エラー修正メカニズムです。 catch ブロックのようなもの)です。でエラーが発生した場合 handleErrorOne でエラーが発生した場合、次の catch ブロックで捕捉されます ( catch(e2) ) によって捕捉され、以下同様です。

これは明らかにあなたの意図したものではありません。

何が間違っていても、解決チェーン全体が失敗するようにしたいとしましょう。

stepOne()
.then(function(a) {
    return stepTwo(a).then(null, handleErrorTwo);
}, handleErrorOne)
.then(function(b) {
    return stepThree(b).then(null, handleErrorThree);
});

handleErrorOne の場合のみ呼び出されるからです。 stepOne が拒否した場合のみ呼び出されるからです (これはチェーンの最初の関数なので、この時点でチェーンが拒否された場合、その関数の約束のせいでしかありえないことが分かっています)。

重要な変更は、他の関数のエラーハンドラがメインの約束の連鎖の一部ではないことです。その代わりに、各ステップは独自の onRejected があり、ステップが拒否された場合のみ呼び出されます(ただし、メインチェーンから直接到達することはできません)。

これがうまくいく理由は、両方の onFulfilledonRejected はオプションの引数で then メソッドに渡すオプションの引数です。もし、約束が果たされ(つまり、解決され)、次の then が存在しない場合、その連鎖の中で onFulfilled ハンドラを持たない場合、そのようなハンドラを持つものが現れるまでチェーンは継続されます。

これは以下の2行が等価であることを意味します。

stepOne().then(stepTwo, handleErrorOne)
stepOne().then(null, handleErrorOne).then(stepTwo)

しかし、次の行は ではなく は上の二つと同等です。

stepOne().then(stepTwo).then(null, handleErrorOne)

Angularのpromiseライブラリ $q は kriskowal の Q ライブラリ (これはよりリッチな API を持ちます。 $q ). Qの API ドキュメント を参照してください。Qは Promises/A+仕様 を実装しており、どのように then とプロミスの解決動作が正確にどのように動作するかについて詳しく説明されています。

をEDITしました。

また、エラーハンドラでチェーンから抜け出したい場合は、rejected promiseを返すか、Errorを投げる必要があることも覚えておいてください(これは自動的にrejected promiseに捕捉・ラップされます)。もし、プロミスを返さないのであれば then は戻り値をresolveプロミスにラップしてくれます。

これは、何も返さない場合、事実上、解決されたプロミスを値として返していることを意味します。 undefined .