2016-07-28 12 views
1

私はE6 Promisesで始まります。私は非常に好きですが、私が理解していないエラー処理に関する重要な概念があり、明確化が大好きです。ES6 Promiseエラーが期待どおりにバブリングしない

の約束を返し、次の簡単な関数と仮定してみましょう:ちょうど(それに渡された文字列の約束を返し、その約束が解決または拒否することになり、

function promiseString(str, timeout, doResolve) { 
     return new Promise((resolve, reject) => { 
      setTimeout(() => { 
       if (doResolve) { 
        resolve(str); 
       } else { 
        reject(new Error("Rejecting " + str)); 
       } 
      }, timeout); 
     }); 
    } 

それは非常に簡単ですが3番目の引数に基づいて) "timeout"ミリ秒で指定します。

次のように私は期待を完全として、これを消費することができます。

  promiseString("One", 100, true) 
       .then((str) => { console.log("First then is " + str); return promiseString(str + " two", 100, true); }) 
       .then((str) => { console.log("Second then is " + str); return promiseString(str + " three", 100, true); }) 
       .then((str) => console.log(str)) 
       .catch((err) => console.error(err)); 

このチェーンのコールのいずれかで「偽」から「真」に三番目の引数を変更する場合は、予想通り、私のエラーがキャッチされますconsole.error()に送信します。

しかし、今有望なオブジェクトを構築するために、以下の(同様に愚かな)関数を想像:

function DoublePromiser(str1, str2, doResolve) { 
     this.promise = new Promise((resolve, reject) => { 
      promiseString(str1, 100, doResolve) 
       .then((s1) => promiseString(s1 + str2, 100, doResolve)) 
       .then((s2) => resolve(s2)); 
     }); 
    } 

は(doResolveに設定され、解決すべてと拒否何で、次のように私はこのコードを消費することになりました想像してみて)真:

  var dp = new DoublePromiser("Big", "Promise", true); 
      dp.promise 
       .then((s) => console.log("DoublePromise: " + s)) 
       .catch((err)=>console.log("I did catch: ", err.message)); 

予想されるように、私は、コンソールに以下を参照してください。

DoublePromise: BigPromise

しかし、今私は(拒否するように私の約束ルーチンを引き起こす)、「偽」にdoResolveを設定し、消費するコードを変更:

  var dp = new DoublePromiser("Big", "Promise", false); 
      dp.promise 
       .then((s) => console.log("DoublePromise: " + s)) 
       .catch((err)=>console.log("I did catch: ", err.message)); 

ため、エラーが「バブルアップ」すべきで、私が期待する方法の私の理解で次のように記録するコンソール:

I did catch: Rejecting Big

しかし、そうではありません。代わりに、コンソールが不明なエラーを示しています

Uncaught (in promise) Error: Rejecting Big

私は私が期待して(と希望)ものを手に入れる私はこのように、DoublePromiserにおけるチェーンの最後にキャッチを追加した場合:

function DoublePromiser(str1, str2, doResolve) { 
     this.promise = new Promise((resolve, reject) => { 
      promiseString(str1, 100, doResolve) 
       .then((s1) => promiseString(s1 + str2, 100, doResolve)) 
       .then((s2) => resolve(s2)) 
       .catch((err) => reject(err)); // ADDING THIS TO MAKE IT WORK 
     }); 
    } 

今私は私が期待していることを得る、エラーはキャッチされていません。しかし、これは、エラーがバブルアップするという考え全体に反しているようです。同じエラーを再度拒否するだけでエラーをキャッチするのは変です。

これを簡単に動作させる方法がありませんか?

私はいくつかの基本的な概念が欠けていますか?

+0

実際の問題を述べていないメイクアップコードを使用したこれらの100%理論的な質問は、スタックオーバーフローではうまく機能しません。 – jfriend00

+0

また、プロミスコンストラクタanti-patternを使用しています。https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns – jfriend00

+0

@estus - タイトルを編集しました。 – jfriend00

答えて

3

プロミスコンストラクタのアンチパターンを使用しています。既存の約束を別の約束で包んではいけません。それは、物事が適切に働くように多くの余分な仕事をするだけで、大部分の人は余分な仕事を適切に行なわないので、プログラミングミスも起こりやすいからです。あなたがすでに持っている約束を返してください。

function DoublePromiser(str1, str2, doResolve) { 
    this.promise = new Promise((resolve, reject) => { 
     promiseString(str1, 100, doResolve) 
      .then((s1) => promiseString(s1 + str2, 100, doResolve)) 
      .then((s2) => resolve(s2)) 
      .catch((err) => reject(err)); // ADDING THIS TO MAKE IT WORK 
    }); 
} 

これに:この

変更

DoublePromiser("Big", "Promise", false).then(...); 

要約:あなたほぼ

function DoublePromiser(str1, str2, doResolve) { 
    return promiseString(str1, 100, doResolve) 
     .then((s1) => promiseString(s1 + str2, 100, doResolve)); 
} 

そして、その後、ちょうど関数としてそれを使用しますアル入れ子にされたエラーが上向きに伝播し、正しく非同期操作を連鎖/順序づけることができるので、.then()ハンドラ内から内側の約束を返すことになります。

また、既存の約束事を取り巻くことを避けるためには、既存の約束事に連鎖したり、返すことができます。 .catch()ハンドラ内で拒否された約束やスローを返さない限り

はまた、そこから約束チェーンを続け、あなたが.catch()をすれば、それは拒否された約束を「ハンドル」と新たな非拒否約束を返すことに注意してください例外。だから、この:.catch()が約束チェーンは喜んで続けて約束を「取り扱う」ため

p.catch((err) => console.log(err)).then(() => console.log("chain continues")) 

は喜んで両方console.log()のステートメントを実行します。


私は私の以前のコメントで述べたように、これらの100%の理論的な議論は、あなたが本当にどのように20ページのチュートリアルせずに(私たちは本当の問題が何であるかを推測する必要が)達成したい正確に何を得るのは難しいです多くのものをカバーする仕事を約束します。あなたがこのテクニックで解決しようとしている現実世界の問題を投稿して、それを行うための最善の方法をいくつかのコード行と説明のいくつかの段落で表示/説明することは、ずっと良いことです。

+0

これはあなたの仕事のためによくありがとう。私は明日のあなたの答えに取り組んでいます。これの "現実の"バージョンは非常に大きく、StackOverflowのために簡潔に記述するのは難しいです。これは、SAASシステム用のIndexedDbを使用してキャッシングシステムを作成することとは関係がありますが、かなり複雑なキャッシングシステムです。私はかなりの時間をこの「偽の世界」の抜粋に「現実の世界」の問題を沸かせました。 現在の設計では、コンストラクタを使用してオブジェクトを作成する必要がありますが、私は次の約束をしたり、どこで手に入るかを見たりすることはしません。 –

+0

そして....これが私がStackOverflowを愛する理由です。多くのスペック文書とチュートリアルを読んで、これを "ほとんど"正しいものにした後、ペニーは最終的に "アンチパターン"とネストに落ちました。そして、それはコンストラクタで同じことをするのがうまく動作します。完璧。ありがとうございました。 –

+0

@StephanGolux - 素晴らしい。コンストラクタの問題は、それが約束を返せないということです。しかし、あなたはインスタンスデータで約束を守り、コンストラクタを呼び出した後にそれを得るために手を入れています。それは私には奇妙に思えるかもしれませんが、オブジェクト/コンストラクタになるための他の目的を開示していない可能性があります。 – jfriend00

関連する問題