同期イテラブルでの待機に使用する


11

MDNによると for await...of、2つのユースケースがあります。

このfor await...ofステートメントは、非同期反復可能オブジェクトだけでなく、同期反復可能オブジェクトに対してもループするループを作成します...

私は以前に前者を知っていました:を使用しSymbol.asyncIteratorた非同期反復可能オブジェクト。しかし、今は後者に興味があります。同期イテラブルです。

次のコードは、同期イテラブル(promiseの配列)を反復処理します。それは、各約束の履行の進展を妨げるように見えます。

async function asyncFunction() {
    try {
        const happy = new Promise((resolve)=>setTimeout(()=>resolve('happy'), 1000))
        const sad = new Promise((_,reject)=>setTimeout(()=>reject('sad')))
        const promises = [happy, sad]
        for await(const item of promises) {
            console.log(item)
        }
    } catch (err) {
        console.log(`an error occurred:`, err)
    }
}

asyncFunction() // "happy, an error occurred: sad" (printed in quick succession, after about 5 seconds)

以下に示すロジックに従って、この動作は各プロミスを順番に待つのと同じように見えます。この主張は正しいですか?

このコードのパターンには暗黙の拒否によるワイヤーアップの落とし穴がPromise.allありPromise.allSettled、それを回避するため、このパターンが言語によって明示的にサポートされているのは奇妙に思えます。


2
あなたの質問は正確には何ですか?それはあなたが仕事に提供する実施例のように思える
鷺リカ

for await... of同期イテラブルを使用した私の説明は正しいですか?そうである場合、そのパターンが未処理の拒否エラーを出力する可能性があることは重要ですか?
ベンアストン

「それは正しいですか」は問題ではありません。「正しい」とは、あなたが言うとおりです。
Robert Harvey

あなたが説明した未処理の拒否エラーの発生をコードで実証できますか?
Robert Harvey

最終的なコードはそれを示しています。正しいとは、このコンテキストでは明確に定義された意味を持っているからです。私が考えていることを説明するコードを提供したからです。動作が私のコードと一致する場合、私のコードは正しいです。それ以外の場合、私の理解は正しくありません。また、「正しい」という観察は、あなたが言うとおりです。明らかに正しくありません。正しいとは、この文脈では明確に定義された意味を持っています。
ベンアストン

回答:


4

はい、それは奇妙です、そしてあなたはこれをするべきではありません。promiseの配列を反復しないでください。これは、あなたが言及した未処理の拒否の問題に正確につながります

では、なぜこれが言語でサポートされているのでしょうか?ずさんな約束のセマンティクスを続ける。

正確な理由は、提案のこの部分について議論している問題のこのコメントにあります。

私たちはにフォールバックすべきだと思うSymbol.iterator私たちの現在の約束の意味が同期物事が非同期なものとして使用できるようにすることについてのすべてですので。これを「だらしない」と呼ぶかもしれません。上記の@groundwaterのロジックに従います が、類似点を詳しく説明したいだけです。

の「連鎖」セマンティクスは.then、これについてすべてです。Promise from .thenまたはスカラー値を返すことができます。それはすべて同じです。Promise.resolvePromiseで何かをラップするのではなく、何かをPromiseにキャストするように呼び出し ます。何かがある場合は非同期の値を取得します。

意味asyncawaitすべて同様にずさんであることについてです。awaitジョブキューに制御を委譲することを除いて、非同期関数内の任意の非Promise式を平手打ちすることができ、すべてがまったく同じように正常に機能します。同様に、結果が得async られる限り、あなたが望むものを「防御的に」置くことができますawait。Promiseを返す関数がある場合-何でも!あなたはそれをasync機能させることができ 、ユーザーの観点からは、何も変更されません(技術的には、別のPromiseオブジェクトを取得したとしても)。

非同期イテレータとジェネレータは同じように動作するはずです。誤ってPromiseでなかった値を待つことができるのと同じように、合理的なユーザーはyield*、非同期ジェネレーター内の同期イテレーターを期待できます。for awaitユーザーが非同期的にイテレータを取得している可能性があると考えて、ユーザーがそのように防御的にループをマークした場合、ループも同様に「正常に機能する」はずです。

これらすべての類似点を打破することは大きな問題になると思います。これにより、非同期イテレータの人間工学性が低下します。次回、非同期ジェネレーター/イテレーターがTC39の議題に登場するときに、これについて話し合いましょう。


ありがとうございました。イベントが発生していますか、それとも実際には他の種類のエラーですか?イベントはWebAPIの一部だと思ったので、質問します。イベントの発行は、仕様の他の部分でも同様に使用されていますか?
ベンアストン

@ 52d6c6af unhandledrejectionイベントのことですか?
ベルギ

はい。私が使用した「エラー」をインターセプトするのはそれだけですwindow.addEventListener('unhandledrejection',...。要するに、これは、JavaScriptによるこの種のエラーの発生について、私が思い浮かぶことができる唯一のインスタンスです。しかし、これを考えるのは間違いなく間違いです。最後に、この「エラー」の発生は、コンソールに不要なエラーメッセージが表示される以上に本当に重要なのでしょうか。
ベンアストン

1
@を参照してください52d6c6af ここそこにこれはECMAScriptのとWeb APIの仕様の間の共同の努力で指定されているかについて。いいえ、イベントはそれほど重要ではありません。これを取得するのはすでに遅すぎます。Afaics、それはクライアント側のエラーを監視するためにのみ使用されます。
ベルギ

それが本当に重要ではない場合、アドバイスはまだ「promiseの配列を反復しないでください」ですか、それとも「これは特定の状況でフェイルファスト動作を示さないことに注意してください」ですか?
ベンアストン

0

sad約束はされていないことawait、それが失敗したとき編-そのコードは、上で待機して終了する必要がありhappy、それが上の待つ始めることができる前にsadsad約束は前に失敗してhappy解決します。(Promise.allこのユースケースにより適したツールです)


1
知っている。したがって、私の質問です。Promise.allより良い解決策である場合、言語はなぜこの構文に対応するのですか?for await...of非同期の反復可能オブジェクトを単に列挙するように簡単に実装できたでしょう。しかし、彼らは同期イテラブルを列挙するためにそれを用意しました(ただし、(見かけは?)落とし穴があります)。どうして?
ベンアストン

1
あ、誤解しました。for await ... of同期イテラブルを受け入れる理由を尋ねていますか?条件付きで同期アイテムを返す非同期ジェネレーターをサポートすると思います。
Gershom

はい、特にそれが拒絶の結末の落とし穴を導入するように見えることを考えると、そうです。
ベンアストン

私の意見では、落とし穴は、より一般的には約束を作成することであり、すぐにそれを待つことではありません。残念ながら、この落とし穴もしばしば非常に便利な機能です。
Gershom
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.