JavaScriptでforループ中にsleepしたい
setTimeout
JavaScriptではsetTimeoutを使ってsleepします。
const start = Date.now();
// 500ミリ秒sleep
window.setTimeout(() => {
console.log("run: " + (Date.now() - start) + " msec");
}, 500);
> run: 501 msec
このsetTimeoutを使って、ループ間のsleepを設定します。
const start = Date.now();
// 500ミリ秒毎にループを実行したいが...
for (let i = 0; i < 5; i++) {
window.setTimeout(() => {
console.log("run: " + (Date.now() - start) + " msec");
}, 500);
}
パット見よさそうですが、これでは「500ミリ秒後に関数を実行 x 5回」となってしまいます。
// setTimeoutで指定した関数が、500ミリ秒後にすべて呼び出される
> run: 500 msec
> run: 501 msec
> run: 501 msec
> run: 501 msec
> run: 501 msec
このように、ループの中で単純にsetTimeoutを呼び出しても期待する動作になりません。
ループ毎にsleep
ループ終了時に次のループ処理をsetTimeoutすることで、ループ毎にsleepする動作を実現できます。
/**
* @param func : (val: any) => any 1ループの処理関数
* @param count: number ループ回数
* @param sleep: number sleepミリ秒
* @param val : any = {} 処理関数に渡す引数
*/
function intervalLoop(func, count, sleep, val = {}) {
window.setTimeout(() => {
const result = func(val);
if (count > 1) {
intervalLoop(func, --count, sleep, result);
}
}, sleep);
}
TypeScript版
function intervalLoop(func: (val: any) => any, count: number, sleep: number, val: any = {}) {
window.setTimeout(() => {
const result = func(val);
if (count > 1) {
intervalLoop(func, --count, sleep, result);
}
}, sleep);
}
ループ結果をフィードバックできるように、処理関数の結果を引数で受け取れるようにしています。
intervalLoop(start => {
console.log("run: " + (Date.now() - start) + " msec");
return start;
}, 5, 500, Date.now());
// 500ミリ秒後に次のループが動作している
> run: 501 msec
> run: 1003 msec
> run: 1503 msec
> run: 2007 msec
> run: 2509 msec