多くのプログラミング言語には、プログラムを一時的に停止させるための「sleep」という機能が用意されています。
sleepを使用することで、特定の処理を指定した時間だけストップさせられるので、時間差で処理を実行したいときなどに便利です。
一方で、JavaScriptではこのsleep機能は言語仕様に含まれておらず、自分で実装する必要があります。
そこで今回の記事では、JavaScriptでsleep機能を実装する方法について解説していきたいと思います!
sleepとは?
sleepとは、多くの言語で主に関数として実装されている、プログラムの動きを一時的に停止させるための機能です。指定の時間に処理を実行させたり、一定の間隔で処理を実行させたい場合に使用することができます。
例えば、現在時刻を元に指定の時間までの秒数を計算し、その時間分だけ処理を待機させることで、任意の時刻に処理を実行させることができるようになります。
また、一度に処理しようとするとCPUの処理量が膨大になってしまうような作業の場合に、sleepを使って一定間隔に処理を分けることで、負担を軽減させることもできます。
その他にも、非同期処理でタスクを実行する際に、状況に応じて処理順を制御したい場合などにもsleepの一時停止機能は役立ちます。(非同期処理が何かについては後ほど説明します)
このように、様々な場面で活用できるsleepですが、残念ながらJavaScriptには直接的に扱うための機能が用意されていません。
そのため、この記事ではJavaScriptの機能を利用して擬似的にsleep機能を実装する方法について紹介します。
タイマーを利用する
まずは、タイマー処理を使って実装する方法について解説していきます。
タイマー処理とは、指定の時間が経過した後に任意の処理を実行させるための機能です。1度のみ処理を実行させる関数と、繰り返し処理を実行させる関数の2つが主なタイマー処理機能として用意されています。
それぞれの使用方法について見ていきましょう。
setTimeout関数を使用する
初めに、setTimeout関数を使用する方法から説明します。先ほど紹介した2つの関数のうち、1度のみ処理を実行させる方であるのが、このsetTimeout関数です。
setTimeout関数を使う際の基本的な構文例は以下の通りです。
【基本構文】
setTimeout(コールバック関数, ミリ秒単位の時間);
setTimeout関数の引数に指定するのは、主に実行させたい処理(関数)と待ち時間の2つです。実行する関数に引数を渡したい場合は、時間指定の後に続けて値を記述します。
時間の指定はミリ秒 (1/1000 秒)単位で行うので、例えば1秒後に実行させたい場合は「1000」と指定します。
実際にsetTimeout関数を使う場合は、引数に渡す関数をなるべく分けて記述する方がコードが見やすくなります。
【サンプルコード】
// 関数を宣言
function sample1() {
console.log("sample1");
}
// 変数としても使えます
const sample2 = function () {
console.log("sample2");
}
setTimeout(sample1, 1000);
setTimeout(sample2, 2000);
【実行結果】
sample1 // 実行してから1秒後に表示
sample2 // 実行してから2秒後に表示
上記の例を実行すると、それぞれ1秒後と2秒後にログが表示されます。
このように、特定の処理の実行タイミングを遅らせたい場合にsetTimeout関数は有効です。
ただし、あくまで処理の実行タイミングを変更するための関数なので、setTimeout関数より後に記述したコードは関数の処理結果を待たずに先に実行されます。
そのため、実行完了後に行いたい処理は全て引数の関数内に記述しなければいけないわけですが、内容によっては通称コールバック地獄と呼ばれるような複雑な入れ子状態が発生してしまいます。無理にsetTimeout関数で実装しようとすると、可読性が下がる原因になりかねません。
例えば、同じ動作をphpのsleep関数とJavaScriptのsetTimeout関数で記述した場合に、こんなにも見づらさが変わってしまいます。
【PHPの場合】
sleep(1);
echo "1秒経ちました。"
sleep(1);
echo "2秒経ちました。"
【JavaScriptの場合】
setTimeout(function () {
console.log("1秒経ちました。");
setTimeout(function () {
console.log("2秒経ちました。");
}, 1000);
}, 1000);
上記のJavaScriptのコードが、いわゆる入れ子状態(ネスト)です。
同じような記述を一度繰り返しただけでも、コードの読みにくさが増したことが分かると思います。
処理順を厳密に指定したい場合は、setTimeout関数のみで実装するのではなく、後ほど紹介するPromiseオブジェクトと組み合わせて活用するのがいいでしょう。
setInterval関数を使用する
次に、setInterval関数の使い方について説明していきます。
こちらは、一定時間ごとに同じ処理を繰り返したい場合に使用する関数になります。
基本的な構文は先ほどのsetTimeout関数とほとんど変わりませんが、setInterval関数の場合はタイマーを停止させるためのclearInterval関数を必ず実行する必要があります。そうしないと、同じ処理を永遠に繰り返し続けることになってしまいます。
以下のサンプルコードで実際の動きを見てみましょう。
【サンプルコード】
// sampleIntervalを実行する関数を宣言
function sampleInterval(interval) {
let counter = 0;
// 5回同じ処理を繰り返すsampleInterval関数
const showHello = setInterval(function () {
console.log("Hello!");
counter++;
// 5回目に達したらclearInterval関数で停止させる
if (counter === 5) {
clearInterval(showHello);
console.log("完了");
}
}, interval);
}
【実行結果】
"Hello!"
"Hello!"
"Hello!"
"Hello!"
"Hello!"
"完了"
clearInterval関数の引数に渡すため、setInterval関数は変数として宣言しています。同じ処理が繰り返されるたびにカウント数が加算されていくので、5回目に到達した時点で停止するようif文で条件分けをして、その条件下でclearInterval関数を実行しています。
このように、ループ処理内でsleep関数を使用するのと同等の動きを、setInterval関数で実現することができます。
Promiseを利用してsleep機能を作る
先ほどの説明でも少し触れましたが、コードの実行順を厳密に定めたい場合において、setTimeout関数はあまり使用に適していません。
そこで活用するのが、Promiseオブジェクトです。
Promiseオブジェクトは、引数に指定した処理が完了した際に、その処理が成功したか否かを結果として受け取ることができるオブジェクトです。
Promiseオブジェクトには、「PromiseStatus」という処理状態を表すステータスがあり、以下の3つで実行結果を表します。
- pending: 処理中
- resolved: 処理が成功した状態
- rejected: 処理が失敗した状態
インスタンス作成時はこのステータスがpending状態となっており、resolvedに移行するとthenメソッドが、rejectedに移行した場合にはcatchメソッドが続けて実行されます。
各メソッドの返り値でPromiseオブジェクトを返すことで、複数回続けてメソッドを実行することも可能です。この方法を利用することで、任意の順番で処理を実行することができるようになります。
実際のサンプルコードを見てみましょう。
【サンプルコード】
// インスタンスを作成
new Promise(function (resolve) {
setTimeout(function () {
console.log("1番目");
// ステータスをresolveに移行
resolve("2番目");
}, 1000);
})
.then(function (val) {
setTimeout(function () {
console.log(val);
}, 1000);
});
【実行結果】
1番目
2番目
Promiseオブジェクトの引数には関数を渡します。その関数の第一引数にresolve関数を、第二引数には任意でreject関数を指定します。(引数名は分かりやすいように記述しているだけなので、実際には任意の名前をつけられます)
処理が完了した後、引数として受け取ったresolve関数かreject関数のどちらかを実行することで、Promiseオブジェクトのステータスが変化します。
上記のコードではresolve関数を実行しているので、Promiseオブジェクトのステータスはresolvedへと移行し、thenメソッドが続いて実行されます。
この際にポイントなのが、resolve関数やreject関数にも引数を渡すことができる点です。
渡した値はPromiseオブジェクトの「PromiseValue」に格納され、thenメソッドの引数として受け取ることができます。
JavaScriptの非同期処理とは?
プログラムは基本的に、上から下へと記述した順にコードを処理します。この処理方法のことを、同期処理と言います。
同期処理では、前の行に記述した処理が完全に終わるまで次の行に移ることができないため、通信処理などの重い作業を行なった場合に、プログラム全体の処理が遅れてしまうというデメリットがあります。
このデメリットを解消するために用意されているのが、非同期処理という処理方法です。
非同期処理の最大のメリットは、前の処理の完了を待つことなく次の処理を開始することができるという点にあります。これにより、データの取得と画面描写を並行して行うなど、複数のタスクを同時に処理することができます。
これまで紹介してきたタイマー処理やPromiseオブジェクトも、非同期処理の一部です。
async/awaitを利用してsleep機能を作る
非同期処理を活用する方法として有名な「async / await」を利用して、sleep機能を実現する方法について紹介します。
asyncと await は、非同期処理を行うための機能の一つであり、先ほど紹介した「Promise.then」をより見やすく記述するための方法でもあります。
関数の頭に async と付けることで、その関数をPromiseオブジェクトを返す非同期関数として定義することができます。
【サンプルコード】
async function sample() {
return 1;
}
await は async関数内のみで使用できる演算子です。
awaitを使用すると、Promiseオブジェクトが返却されるまで関数内の処理が一時停止されるため、同期的にコードを処理することができます。
試しに、以下のサンプルの動きを await のある無しで比較してみてください。
【サンプルコード】
async function sample2() {
new Promise(resolve => {
setTimeout(() => {
console.log("5秒経過");
resolve();
}, 5000)
});
console.log("Hello!");
}
【awaitありの場合の実行結果】
▶ Promise {<pending>}
5秒経過
Hello!
【awaitなしの場合の実行結果】
Hello!
▶ Promise {<fulfilled>: undefined}
5秒経過
ログの表示される順番が変わるのが分かるかと思います。
このように、Promiseオブジェクトの処理を待ってからthenメソッドの処理に移行するという動きを、 async と await を使って書き換えることができます。
【番外編】jQueryでsleep機能を作る
JavaScriptのライブラリの1つであるjQueryを使用する場合は、Deferredオブジェクトを利用してsleep機能を実装することができます。
Deferredオブジェクトもまた、非同期処理を扱うためのオブジェクトです。
Promiseと同様に3つのステータスで処理状態を表し、Promiseオブジェクトを結果として返すことができます。
以下のサンプルコードを見てみましょう。
【サンプルコード】
const sleep = function () {
const def = new $.Deferred();
setTimeout(() => {
console.log("3秒経過");
def.resolve();
}, 3000);
return def.promise();
}
async function sample() {
await sleep();
console.log("Hello!");
}
sample();
【実行結果】
3秒経過
Hello!
Deferredオブジェクトを作成後、処理が完了した段階でresolveを実行してステータスを変更しています。その後に、「def.promise()」でPromiseオブジェクトを返却しています。
上記のコードからも分かるように、Promiseオブジェクトが返されるので「async/await」と組み合わせて使用することもできます。
【応用】一行でsleep機能を実装する
最後に、sleep機能を簡単に実装したい方のために、一行で記述する方法を紹介します。
基本的には、この方法でほとんどの場面に対応できるかと思いますので、ぜひ覚えてみてください。
まず、以下の一行を記述しましょう。
const sleep = time => new Promise(resolve => setTimeout(resolve, time));
機能の実装はこれだけで完了です。
作成したこのsleep変数を、async関数内の実行したい箇所でawaitの後に記述するだけで、sleep機能を簡単に実行することができます。
上記のコードはアロー関数という記述方法を使っているので、見慣れない方は内容が少し読み取りにくいかもしれませんが、この記述方法を覚えておくと他の場面でも有効活用することができます。
余裕があれば、アロー関数についても調べてみてください。
実際に使用する場合のサンプルコードを見てみましょう。
【サンプルコード】
const sleep = time => new Promise(resolve => setTimeout(resolve, time));
async function example() {
console.log('Start');
await sleep(2000); // 2秒待つ
console.log('End');
}
example();
【実行結果】
Start
▶ Promise {<pending>}
End
まとめ
JavaScriptでsleep機能を扱う場合、非同期処理についても理解しなければいけないため、難しく感じる人もいるかもしれません。
ですが、非同期処理を使いこなすことができればJavaScriptを使ってできることが一気に広がります。
慣れるまで何度もコードを試したり、記事を読み返したりしながら、使い方を覚えていきましょう!
関連記事
- JavaScriptとは?初心者向けにできることや基本的な書き方を解説
- JavaScriptが初心者におススメな理由を現役プログラマーが解説
- 【JavaScript入門】簡単なサンプルコードを実行して習得
- 【JavaScript入門】getElementByIdの使い方をわかりやすく徹底解説
JavaScriptの勉強方法は?
書籍やインターネットで学習する方法があります。昨今では、YouTubeなどの動画サイトやエンジニアのコミュニティサイトなども充実していて多くの情報が手に入ります。
そして、より効率的に知識・スキルを習得するには、知識をつけながら実際に手を動かしてみるなど、インプットとアウトプットを繰り返していくことが重要です。特に独学の場合は、有識者に質問ができたりフィードバックをもらえるような環境があると、理解度が深まるでしょう。
ただ、JavaScriptに限らず、ITスキルを身につける際、どうしても課題にぶつかってしまうことはありますよね。特に独学だと、わからない部分をプロに質問できる機会を確保しにくく、モチベーションが続きにくいという側面があります。独学でモチベーションを維持する自信がない人にはプログラミングスクールという手もあります。費用は掛かりますが、その分スキルを身につけやすいです。しっかりと知識・スキルを習得して実践に活かしたいという人はプログラミングスクールがおすすめです。
プログラミングスクールならテックマニアがおすすめ!

ITスキル需要の高まりとともにプログラミングスクールも増えました。しかし、どのスクールに通うべきか迷ってしまう人もいるでしょう。そんな方にはテックマニアをおすすめします!これまで多くのITエンジニアを育成・輩出してきたテックマニアでもプログラミングスクールを開講しています。
<テックマニアの特徴>
・たしかな育成実績と親身な教育 ~セカンドキャリアを全力支援~
・講師が現役エンジニア ~“本当”の開発ノウハウを直に学べる~
・専属講師が学習を徹底サポート ~「わからない」を徹底解決~
・実務ベースでスキルを習得 ~実践的な凝縮カリキュラム~
このような特徴を持つテックマニアはITエンジニアのスタートラインとして最適です。
話を聞きたい・詳しく知りたいという方はこちらからお気軽にお問い合わせください。