空雲 Blog

Eye catchTypeScript/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後に終了するPromise
5 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()

実行結果

1undefined
2undefined
3undefined
4undefined
5undefined
6undefined
7undefined
8undefined
9undefined
10undefined
11end

実行確認用

https://www.typescriptlang.org/

解説

肝はPromise.raceです。私は時々使うのですが、一般的なところでは滅多にお目にかかることはありません。この関数は、渡した値の中から待ちが発生していない値を返します。また、複数の処理が終了している場合は、先頭側の値を優先して返します。

この性質を利用して、目的のPromiseの後ろに待つ必要の無い値を入れます。するとPromiseが終了するまでは、そちらの値が返ってくるのです。そしてPromiseが終了した時点で、今度はPromiseが返した値に変化します。

まとめ

Promise.allに比べると日の目を見ないPromise.raceですが、実はとても使えるヤツなので、忘れないであげてください。