記事タイトルの通り、JavaScript という非同期な世界で sleep する方法を考えてみます。もちろん、寝たいわけではなくて、待たせたいわけですよ。なので、wait させたい、とも言えますね。
旧来より JavaScript の世界で指定秒数だけ待たせたい場合は setTimeout() を使ってきました。しかし非同期の処理をシーケンシャルに実行しなければならないシーンが増えた近年では、setTimeout() のコールバック関数方式ではコードの見通しが悪く、できる限り使いたくないというのが本音です。なのでここでは Promise や async/await を使う前提で考えてみましょう。
ワンライナーで手っ取り早く
何度も wait させる必要はなく、一回だけ固定の秒数だけ待たせたいなら、ワンライナーで setTimeout() を Promise 化して await するのが個人的には好きです。
(async () => {
console.time('Waited for');
await new Promise(resolve => setTimeout(resolve, 1000));
console.timeLog('Waited for'); // Waited for: 1002.3310546875 ms
})();
個人的にワンライナーはコードが読み取りにくいので好きではないのですが、この程度なら許容範囲かなと思い、使っています。
関数化で汎用性を
関数化すれば、待たせる部分のコードは短くなりますし、待たせる秒数をパラメーター化すれば汎用性も上がります。
(async () => {
console.time('Waited for');
await wait(1000);
console.timeLog('Waited for'); // Waited for: 1007.2958984375 ms
})();
function wait(msec) {
return new Promise(resolve => setTimeout(resolve, msec));
}
node.js なら Promise 版の setTimeout()
node v16 以降のバージョンであれば Promise 版の setTimeout() が用意されています。node v15 で実験的に実装され、node v16 以降で正式に利用可能になりました。
(async () => {
console.time('Waited for');
await setTimeout(1000);
console.timeLog('Waited for'); // Waited for: 1.003s
})();
もちろん、setTimeout() だけでなく setInterval() や setImmediate() も Promise 化したものが用意されています。筆者はまだ仕事では node v16 の環境でコードを書いたことがないので、普段はまったく Promise 版の setTimeout() は使っていませんが、node v16 が普及したころには頻繁に使ってそうです。
まとめ
ブラウザー上の JavaScript でも、node の Promise 版 setTimeout() が欲しいですよね。これはどの団体が策定するのでしょうね。JavaScript のタイマー関数は window オブジェクトのメソッドなので Ecma International ではなさそう。WHATWG かな?
今回は以上で終わりです。最後まで読んでくださりありがとうございました。それでは次回の記事までごきげんよう。
