web-dev-qa-db-ja.com

JavaScript ES6は「完了した」APIをサポートすることを約束しますか?

例えば

_p = new Promise(function (resolve, reject) {
    throw 'err';
});

p.done();
_

ほとんどのpromise polyfill libsでは、doneはエラーをスローし、現在の実行は終了します。

しかし、p.then()を使用すると、何も起こりません。エラーは約束によって飲み込まれます。 _p.catch_を使用する場合、現在の実行を終了する方法はありません。私は次のようなことを達成したいです:

_try {
    // something
} catch (err) {
    if (check(err)) {
        throw err;
    }
}
_
40
Yad Smood

番号。

だけでなく.done将来のバージョンの仕様ではサポートされない可能性があります-不要です。マリウスがリンクしているスレッドからの引用:

ドメニック:

それでもエラーが発生しやすくなります。スリップしてルールを1回も守らなかった場合、エラーが永久に発生しなくなる可能性があります。

マークミラー(約束の概念を開拓した人):

弱参照がES7でうまくいけば、このギャップを埋めるために必要な診断ツールの1つを提供してくれることに注意してください。弱い参照を使用して、ハンドラに通知せずに拒否されたプロミスが収集された場合、診断を生成するように調整できます。 promiseの実装では、理由をpromiseのエグゼキューター(検死のgcハンドラー)に保持する必要があります。これにより、promiseが拒否されたことが発見された後、診断結果を報告できるようになります。

RSVPのエラーハンドラーに関するYehuda Kats:

RSVPで採用しているアプローチは、デフォルトでスローされる未処理のpromiseモニターをインストールすることです。

非同期エラーハンドラーをアタッチすることがわかっている場合は、noop失敗ハンドラーをアタッチすることで、この動作から特定のプロミスをオプトアウトできます。私たちはおそらくこれのために砂糖を持っています(.undone:p)

私たちの経験では、負担を文字どおりすべての人から非同期エラーハンドラーをアタッチする可能性のある人々に移すことが適切です。

そして、仕様に先行する実際のレポから、ドメニックは言った:

完了した仕事は、未処理の拒否追跡機能を開発ツールに統合することで行われます。ほとんどのTC39erは、私だけでなく私が理解していることから、それを十分に認識していますスペックを完成させるために。


仕様委員会は単に.done、彼らはそれが不必要で間違いを起こしやすいと考えました。新しい最新のプロミスライブラリは、未処理の拒否を自動的に検出します。これの2つの例は、WhenプロミスとBluebirdがアイディアを開拓したプロミスです。

.doneはアーティファクトです-ブラウザが未処理の拒否を検出できなかったという事実に由来します。真実は-それらを決定論的に検出することは不可能ですが、ほとんどの場合、それは完全に可能です。

信じられない? Firefoxを開いて、ネイティブの約束を試してください:

p = new Promise(function (resolve, reject) {
    throw 'err';
});
// Logs as error: Unhandled error: `err`

簡単に言えば、firefoxはガベージコレクションフックを使用して、promiseが未処理の状態で破棄されたことを確認し、デフォルトで画面に書き込むグローバルエラーハンドラーを起動します。

今、問題はネイティブプロミスがまだあまり使用できないことです-IEには存在せず、Chromeには未処理の拒否検出はまだ実装されていませんので-その間、あなたはこの拒否追跡を行うBluebirdのようなES6互換ライブラリを使用することができます。

ポリフィルを行いたい場合(私は強く推奨しない)-torazaburoによるポリフィルにはいくつかの欠点があります。それはpromiseプロトタイプで列挙可能なプロパティを宣言し、通常これは仕様が設計された方法ではありません-モンキーパッチではなく、拡張するためにsubclasspromiseにパッチを当てます-悲しいことに現在これをサポートする実装はありません。

要するに:

  • ネイティブプロミスが安定するまで待ってから使用してください。その間、Bluebirdのような仕様を実装するライブラリを使用できます。安定しない時は.doneはまったく問題になりません。
  • エラーを検出するためのパターンを利用します-たとえば、チェックアウト ディスポーザパターン ここをチェックしてください。
  • 利用可能な場合は開発者ツールを使用してください。長いスタックトレースと非同期デバッグは大きな利点です。また、意味のあるスタックトレースが必要な場合は、文字列をスローしないでください。

幸運と幸せなコーディング。

47

いいえ、AFAIK doneは仕様の一部ではありません。その動作を模倣するには、promiseチェーンの範囲外の次のティックで例外をスローする必要があります。

p.catch(function(e) { 
    setTimeout(function() { throw e; });
});

これは基本的にライブラリがdoneを実装する方法です。 Qドキュメントからの抜粋を参照してください。

thenによく似ていますが、...結果の拒否理由は例外としてスローされますイベントループの将来のターンで

doneを自分で実装する

通常理解されているdoneのおおよそのセマンティクスを実装する場合は、次のようになります。

Promise.prototype.done = function(onFulfilled, onRejected) {
    this
        .then(onFulfilled, onRejected)
        .catch(function(e) {
            setTimeout(function() { throw e; });
        })
    ;
};

エラーハンドラーの設定

これらのエラーを自分で処理する機会が必要な場合は、エラーハンドラを設定できます。

Promise.onError = function(e) {
    console.log("The sky is falling", e);
    throw e;
};

次に、次のティックでハンドラーを呼び出します。

Promise.prototype.done = function(onFulfilled, onRejected) {
    this
        .then(onFulfilled, onRejected)
        .catch(function(e) {
            setTimeout(Promise.onError || function() { throw e; }, 1, e);
        })
    ;
};
19
user663031

TC39の現在の声明では、この問題は、開発者ツールを備えたブラウザーエンジンでネイティブに解決できる可能性があり、解決する必要があります。そのため、ネイティブAPI内でdoneを提供することは反対です。

それは確かに物議を醸している決定です、その問題に関する議論については以下のリンクを参照してください:

https://github.com/domenic/promises-unwrapping/issues/19

http://mozilla.6506.n7.nabble.com/Where-d-Promise-done-go-td281461.html

https://github.com/promises-aplus/promises-spec/issues/4

https://github.com/slightlyoff/Promises/issues/

3
Mariusz Nowak