TypeScript/JavaScriptでPromiseの終了を待たないawaitの利用方法
publication: 2022/10/20
update:2024/02/20
Promiseの終了を待たないawaitの利用方法
Promiseは不便?
Promiseで非同期のプログラムを組む際、対象のPromiseはresolveを呼び出して実行を完了しているのか、それともまだ実行中なのかを判断したいことがあります。しかし単純にawaitで状態を確認しようとしても、終了まで処理がブロックされてしまいます。また、thenの実行時にフラグを操作すれば状態を確認することは可能ですが、それなりに書き方が冗長になります。
「await時にまだ処理が終了していなければ、ブロックせずに実行中であることを識別できる値を返す」というのが可能なら話は簡単です。実はこれ、かなり簡単に書くことが出来ます。
ソースコード
1const main = async () => {2 // ウエイト用3 const sleep = (msec: number) => new Promise(resolve => setTimeout(resolve, msec))4 // 1000ms後に終了するPromise5 const p = new Promise(resolve => setTimeout(() => resolve("end"), 1000))6 while (true) {7 // pが終了していなければ即座にundefinedが返り、終了したらendが返る8 const result = await Promise.race([p, undefined])9 console.log(result)10 if (result)11 break;12 // 100ms待つ13 await sleep(100);14 }15}16main()
実行結果
1undefined2undefined3undefined4undefined5undefined6undefined7undefined8undefined9undefined10undefined11end
実行確認用
https://www.typescriptlang.org/
解説
肝はPromise.raceです。私は時々使うのですが、一般的なところでは滅多にお目にかかることはありません。この関数は、渡した値の中から待ちが発生していない値を返します。また、複数の処理が終了している場合は、先頭側の値を優先して返します。
この性質を利用して、目的のPromiseの後ろに待つ必要の無い値を入れます。するとPromiseが終了するまでは、そちらの値が返ってくるのです。そしてPromiseが終了した時点で、今度はPromiseが返した値に変化します。
まとめ
Promise.allに比べると日の目を見ないPromise.raceですが、実はとても使えるヤツなので、忘れないであげてください。