-ao- ramune blog

©2020 unio / GO2直営からふるラムネ

JavaScriptでforループ中にsleepしたい

2019年10月01日
  • JavaScript

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
                
            
プロフィール画像
なかのひと:unio

数十年前の牧歌的なインターネッツが好きだった、永遠のモラトリアム人。 ただ、モラトリアムしててもお金は増えないので、しゃかいの厳しさを斜め後ろから眺めつつほそぼそと生活しています。

Twitter GitHub
[広告]