MENU

JavaScriptタイマー処理同期・非同期

【JavaScript】 一定時間停止(sleep)のやりかた

更新日:2021/08/24

 

 

プログラムをしていると、一定時間待機してから次のコードを実行したいときがあります。
他の言語ではsleep関数などの名前で実装されていることがあります。

 

しかしJavaScriptには用意されていません。
ここでは、sleep関数のように一定時間待機する方法をお伝えします。

 

一定時間停止するsleep関数

 

ここで紹介するのは、指定時間以上経過後に後続のコードを実行する関数です。
正確な時間待機するものではありません。
場合によっては、大幅に遅延する可能性があります。

 

sleep関数

 

一定時間停止するsleep関数は、次のようなコードで実現できます。

 

一定時間停止するsleep関数

 


const sleep = waitTime => new Promise( resolve => setTimeout(resolve, waitTime) );

 

waitTimeはミリ秒で指定してください。

 

この関数の呼び出し側は、async関数である必要があります。

 

sleep関数の呼び出し

 


const aFunc = async function( ){

    // なんらかの処理

    await sleep( 3000 );

     // なんらかの処理

    await sleep( 1000 );

     // なんらかの処理

}

 

コールバック関数などで処理する場合は、直接呼び出します。

 

ボタンがクリックされたasync関数を呼び出す

 


window.addEventListener( "DOMContentLoaded" , ()=> {
    document.getElementById("btn").addEventListener("click",aFunc);
});

 

上のコードはsleep中にクリックすると、aFuncが呼び出されます。
そのため同じ処理が見かけ上、並列で動作します。

 

必要に応じてフラグ等で管理してください。

 

クリック時に他の関数を経由する場合、async関数の最初のsleepで呼び出し元に処理が戻り、後に続くコードが実行されます。

 


const clickFunc = ()=>{

    aFunc( );
    // aFunc( )の最初のsleep( )でここに戻る
    
    console.log( "aFunc End" ); // aFuncが終了していないのに、Endになる!

}

 

初心者がハマる原因の一つです。

 

 

Node.jsの場合

 

Node.jsのv15.0.0から、Promiseを返すsetTimeoutが導入されました。
そのため、次のようなコードでsleepを実現できます。

 

一定時間停止するsleep関数:Node.js

 


const {setTimeout} = require("timers/promises");
// または、import { setTimeout } from "timers/promises";

const sleep = waitTime => setTimeout( waitTime );

 

しかし実際には、直接setTimeoutを呼び出すだけで目的を達成できます。

 

sleep関数の呼び出し:Node.js

 


const aFunc = async function( ){

    // なんらかの処理

    await setTimeout( 3000 );

     // なんらかの処理

    await setTimeout( 1000 );

     // なんらかの処理

}

 

基本はsetTimeoutにより遅延呼び出し

 

ここからは、sleepについての簡単な解説をしていきます。

 

そもそもJavaScriptには、コード処理の流れ上で特定の時間まで一時停止して、その後処理を続行するという機能がありません。

 

一時停止機能はない

 

一時停止機能がない理由

 

JavaScriptはシングルスレッドで動作します。
そのためコードの処理中は、ブラウザ上でのクリックやデータの読み込み終了などを検知できません。
これらを素早く検知することは、ユーザの満足度を下げないためにも必要なことです。

 

そのためには、コード処理の時間をできる限り短くして、クリックイベントなどの検知をおこなうイベントループにできる限りはやく戻す必要があります。

 

このような経緯から、コードの流れを中断するような機能はJavaScriptにとって受け入れることができないのです。

 

代替措置としてのsetTimeout

 

JavaScriptには指定時間経過後にコールバック関数を呼び出すsetTimeoutというメソッドが存在します。

 

コード上の流れとして一時停止できませんが、setTimeoutを使用すれば同じ結果を得ることができます。

 

次のコードは、3秒、および1秒待機後に処理をおこなっています。

 

setTimeoutにより遅延呼び出し

 


    // なんらかの処理
 
    setTimeout( ()=>{

            // なんらかの処理

            setTimeout( ()=>{

                // なんらかの処理

            }, 1000 );

        }, 3000 );

 

コード上で一回だけ待機するならsetTimeoutでもいいのですが、複数回待機すると上記のようにコールバック内でsetTimeoutを呼び出す必要があります。

 

非常にわかり難いコードの出来上がりです。

 

なおsetTimeoutは特性上、指定時間以上経過したときにコールバック関数を呼び出します。
コールバック関数呼び出しが、想定よりも大幅に遅れても仕様として許容されています。
詳しくは次の記事を読んでみてください。
【JavaScript】 タイマー処理/setTimeoutとsetInterval

Promiseでコールバックのネスト回避

 

わかり難いコールバックのネストを少しでもわかりやすくするために、Promiseに置き換えてみます。

 

Promiseにより遅延呼び出し

 


new Promise( resolve => setTimeout(resolve, 3000) )
    .then( ()=>{
        // なんらかの処理
        return new Promise( resolve => setTimeout(resolve, 1000) );
    })
    .then( ()=>{
        // なんらかの処理
    });

 

Promiseの知識がないと、コールバックのネストよりも難解ですね。
Promiseについては次の記事で詳しくお伝えしています。
【JavaScript】 非同期はPromise?解説が難しいので自分で理解してみた

 

上のコードは二つのnew Promise部分を関数化することで、さらにわかりやすくできます。

 

Promise生成を関数化

 


const sleep = waitTime => new Promise( resolve => setTimeout(resolve, waitTime) );

sleep( 3000 )
    .then( ()=>{
        // なんらかの処理
        return sleep( 3000 );
    })
    .then( ()=>{
        // なんらかの処理
    });

 

関数名をsleepとしたことで、一時停止した雰囲気がでてきました。

 

でもなんだか違うという、違和感があります。

async/awaitによる見かけ上の一時待機化

 

なんだか違うという声に押されたのかわかりませんが、JavaScriptにasyncおよびawaitというキーワードが追加されています。

 

これを使うと、見かけ上ですが一時待機機能が実現できます。

 

async/awaitによる見かけ上の一時待機

 


const sleep = waitTime => new Promise( resolve => setTimeout(resolve, waitTime) );

const aFunc = async function( ){

    // なんらかの処理

    await sleep( 3000 );

     // なんらかの処理

    await sleep( 1000 );

     // なんらかの処理

}

 

await はasync関数内のみで使用できます。
またawaitで待機できるのは、Promiseオブジェクトのみです。

 

aFuncを実行すると、sleep()で一時停止しながら、上から順番に処理をおこなっているように見えます。

 

ですが実際には、Promise - then の組み合わせを置き換えたものです。

 

 

asyncとawaitについては、次の記事で詳しくお伝えしています。
【JavaScript】 async/awaitの処理の流れを図で解説します

最後に

 

とりあえず最初のコードをコピペすれば、sleep機能を実現できます。

 

しかしasyncとawaitの知識がないと、意図しないコードが実行される可能性があります。

 

これらの知識も必須ですね。

けーちゃんおススメJavaScript入門書

  • スラスラ読める JavaScript ふりがなプログラミング
  • プログラム未経験者がJavaScript始めるならコレ!
    コードを掲載して自分で理解しろという投げっぱなしな入門書とは異なり、コードに一つ一つどんなことをやっているかをふりがなという形式で解説しています。
    それでいてJavaScriptの基礎と応用を学べる良書です。
  • これからWebをはじめる人のHTML&CSS、JavaScriptのきほんのきほん
  • JavaScriptの機能を実践で活かすにはHTMLやCSSの知識が不可欠です。
    しかしそれらの知識があることが前提として書かれている書籍が多い中、この本は総合的な知識を身に着けることができます。
    HTMLやCSSの知識も不安な方には、ぴったりの一冊です
  •  

    入門書の役割は、自分のやりたいことをネットで調べることができるようになるための、基礎的な知識の獲得です。
    まずはこれらの本でしっかりと基礎知識を身につけましょう。
    そしてもっと高度なことや専門的なことはネットで調べ、情報が足りないと感じたら書籍を購入してください。


    記事の内容について

     

    こんにちはけーちゃんです。
    説明するのって難しいですね。


    「なんか言ってることおかしくない?」
    たぶん、こんなご意見あると思います。

    裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。

    そんなときは、ご意見もらえたら嬉しいです。

    ご意見はこちら。
    https://note.affi-sapo-sv.com/info.php

    【お願い】

    お願い

    ■このページのURL


    ■このページのタイトル


    ■リンクタグ


    ※リンクして頂いた方でご希望者には貴サイトの紹介記事を作成してリンクを設置します。
    サイト上部の問い合わせよりご連絡ください。
    ただしサイトのジャンルによっては、お断りさせていただくことがあります。