JavaScriptでsleepを実装する

Web開発

お疲れ様です。すぺきよです。

今回はWeb開発の小ネタです。

JavaScriptにはsleepがない!?

C言語やPHPなどの一般的なプログラミング言語には標準でsleep、要するに処理を指定時間待機する関数が実装されています。

しかし、実はJavaScriptには標準でsleepを実現するための関数は存在していません。

そのため、昔は非同期通信を使ってPHPのsleepを間接的に使うみたいなテクニックを使っていました。

しかし、ゲームなどのオフラインでも動くようにしたいJavaScriptで作られているWebアプリではこのPHPなどのサーバーサイドの処理を利用したテクニックは使えません。

実装方法と使い方

実装方法

Promiseとasync、awaitキーワードを使って実装します。

具体的には以下のように実装します。

function sleep(millisecond)
{
  return new Promise((resolve) =>
  {
    setTimeout(() =>{
      resolve();
    }, millisecond)
  });
}

使い方

以下のように、asyncの関数内でawaitを使って呼ぶだけです。コンソールに「よ~い・・・」と出てから5秒後に「どん!」が表示されることが確認できると思います。

async内でないとawaitは使えません。また、awaitを忘れると全く意味がないので注意です。

sleepTest();
async function sleepTest()
{
    console.log("よ~い・・・・");
    await sleep(5 * 1000);
    console.log("どん!");
}

実装の原理

Promiseで非同期処理を作り、JavaScript標準のsetTimeoutを使って、指定された秒数後にresolveを呼び出すといったシンプルな作りで実装できます。

Node.jsにはsleepが実装されていた!

PCのターミナルやコマンドプロンプトでJavaScriptを実行できるようにするNode.jsというものがあります。

私が初めて学んだ時には実装されていなかったはずのsleepできる機能が、いつの間にかNode.jsでは標準で実装されていました

使い方は以下のようにします。

const { setTimeout } = require('timers/promises');

sleepTest2();
async function sleepTest2(){
  console.log("だるまさんが");
  await setTimeout(3 * 1000);
  console.log("ころんだ!");
}

リファレンスを調べたところNode.jsのVersion 15から実装されていたようですね。

もうすでにほかでsetTimeoutを使っているとき

Node.jsで新しく実装されたtimersPromises.setTimeoutが便利だからと、既存のプロジェクトでも使うときには注意が必要です。

それはsetTimeoutを使ったコードがプロジェクト内に含まれているときです。

このようなプロジェクトにむやみやたらとtimersPromises.setTimeoutを使おうとしてしまうと、もともとのsetTimeoutと名前がかぶってしまうため、今まで正しく処理が停止していた部分が停止しなくなるという悲惨なことになります。

こういう時は、後から追加するtimersPromises.setTimeoutを、以下のように別名で取り込むとうまくいきます。

const { setTimeout:setTimeoutPromise } = require('timers/promises');

実際の使い方は以下のように書きます。

const { setTimeout:setTimeoutPromise } = require('timers/promises');

main();
async function main(){
    await sleepTest();
    await sleepTest2();
}

function sleep(millisecond)
{
  return new Promise((resolve) =>
  {
    setTimeout(() =>{
      resolve();
    }, millisecond)
    });
}

async function sleepTest()
{
    console.log("よ~い・・・・");
    await sleep(5 * 1000);
    console.log("どん!");
}

async function sleepTest2(){
  console.log("だるまさんが");
  await setTimeoutPromise(3 * 1000);
  console.log("ころんだ!");
}

これでもともとのsetTimeoutを使いつつ、新しいtimersPromises.setTimeoutも使えるようになります。

既存のプロジェクトで、コードのリファクタリングが大変なプロジェクトや、前任者がおらず処理の責任が取れない場合などは使えると思います。

まとめ

今回はJavaScriptでsleepを使う方法について書いてみました。

今後はNode.jsでは独自で実装せずに、標準のtimersPromises.setTimeoutを使ったほうがよさそうですね。ただし、今まで使っていたsetTimeoutと名前がかぶって既存機能が動かなくなる点は注意が必要です。

Webでは相変わらずsleepできる機能が存在しないようなので、まだまだ独自実装は必要そうです。

参考

コメント

タイトルとURLをコピーしました