非同期処理をタイムアウトする
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ これまで使ったことが全くなかった Promise.race を使う時が来た
何かの非同期処理を実行したときに一定時間過ぎても終わってないならエラー扱いにしたいときってありますよね
その非同期処理がタイムアウト機能に対応してれば 時間がすぎれば Promise が reject されたりしそうですが中にはタイムアウトに対応してなかったり 設定してるのになぜか終わってくれないライブラリもあったりします
そういうときのために自分でタイムアウトできるようなものを作ります
まずは基本のタイムアウトとか考えない非同期処理をする関数を用意します
この関数は 非同期関数の fn を実行した結果を返すもので fn の処理が一定以上かかってるようならタイムアウトするようにします
やることは単純で自分で Promise を作って fn の結果を受け取ったら resolve し 受け取るより先に時間がくれば reject します
fn にキャンセル処理があるなら reject 前に入れておきましょう
これで出来はしたのですが あんまり自分で Promise インスタンスを作りたくないです
コールバック関数必要ですし resolve/reject は自分で制御しなくていいほうが楽です
ということで別バージョンも作りました
こっちでは 一定時間後に reject される timeout 関数を用意しておきます
これを使って p 関数を作ると
シンプルになりました
Promise.race は Promise の配列の中のどれかがおわったら resolve されるものです
fn のほうが先に終われば resolve になり timeout のほうが先に終われば reject となります
こっちだと p のような関数に毎回 new Promise しなくて済むので楽です
その非同期処理がタイムアウト機能に対応してれば 時間がすぎれば Promise が reject されたりしそうですが中にはタイムアウトに対応してなかったり 設定してるのになぜか終わってくれないライブラリもあったりします
そういうときのために自分でタイムアウトできるようなものを作ります
まずは基本のタイムアウトとか考えない非同期処理をする関数を用意します
async function p() {
const result = await fn()
return result
}
この関数は 非同期関数の fn を実行した結果を返すもので fn の処理が一定以上かかってるようならタイムアウトするようにします
やることは単純で自分で Promise を作って fn の結果を受け取ったら resolve し 受け取るより先に時間がくれば reject します
async function p(timeout) {
return new Promise(async (resolve, reject) => {
setTimeout(() => {
reject(new Error("timeout"))
}, timeout)
resolve(await fn())
})
}
fn にキャンセル処理があるなら reject 前に入れておきましょう
これで出来はしたのですが あんまり自分で Promise インスタンスを作りたくないです
コールバック関数必要ですし resolve/reject は自分で制御しなくていいほうが楽です
ということで別バージョンも作りました
こっちでは 一定時間後に reject される timeout 関数を用意しておきます
async function timeout(msec) {
return new Promise((_, reject) => setTimeout(reject, msec))
}
これを使って p 関数を作ると
async function p(timeout_ms) {
return Promise.race([fn(), timeout(timeout_ms)])
}
シンプルになりました
Promise.race は Promise の配列の中のどれかがおわったら resolve されるものです
fn のほうが先に終われば resolve になり timeout のほうが先に終われば reject となります
こっちだと p のような関数に毎回 new Promise しなくて済むので楽です