JavaScriptでsleep処理を使いたいと思ったことはありませんか?
プログラミング言語にはsleep関数が標準で用意されていることが多いのですが、JavaScriptにはsleep機能がありません。どうすればJavaScriptでsleep処理を実装できるのでしょうか?
本記事では、setTimeout、Promise、async/awaitを使ったsleep処理の方法をわかりやすく解説します。さらに、APIのrate limit回避やUI制御、アニメーションのスムーズな実行など、実務で役立つ応用方法も詳しく紹介します。
JavaScriptでのsleep処理をマスターして、効率的なコードを書けるようになりましょう!
目次
1.JavaScriptにおけるsleepとは?
他のプログラミング言語では標準機能として実装されているsleep関数が、JavaScriptには実装されていません。なぜJavaScriptにはsleep関数がないのでしょうか? その理由と、sleepが必要になるシチュエーションについて解説します。
JavaScriptにsleep関数が存在しないのはなぜ?
JavaScriptにsleep関数が存在しない理由は、JavaScriptはシングルスレッドのプログラミング言語だからです。
JavaScriptでは1つのスレッドで1つの処理を順番に実行するため、sleep関数のように一定時間停止する機能があると、その間に他の処理がすべて停止してしまいます。処理停止を防ぐためにsleep関数がないのです。
JavaScriptでは処理の停止を避けるためにイベントループが導入されています。
イベントループは、メインスレッドで実行する関数やAPI処理などのタスクを確認し、すぐに実行できない非同期処理を待機キューに送ります。待機キューに送られたタスクは、メインスレッドが空いたタイミングで処理されます。
JavaScriptには処理を停止する仕組みがなく、非同期で一定時間後に実行するという仕組みで動きます。そのため、他のプログラム言語では標準機能であるsleep関数がJavaScriptには存在しないのです。
sleepが必要になる具体的なケース
JavaScriptにsleep関数が存在しないとはいえ、処理を一時的に停止させたり、遅らせたいケースが出てくるはずです。具体的なケースを3つ見てみましょう。
ケース1:ループ処理時の間隔制御
大量データの処理などループ内で重い処理を繰り返すと、CPU負荷が上昇してブラウザがフリーズするおそれがあります。そのリスクを避けるために、処理の間に短い待機時間を入れることで、負荷を軽減できるようになります。
ケース2:APIを連続で呼び出す場合の「rate limit」超過の回避
APIを連続して呼び出す際、リクエストが短時間に集中すると「rate limit」を超えるエラーが発生してしまうかもしれません。API呼び出しの間隔を1秒ずつ空けるなど、一定の待機時間を設けることで、エラーを防ぐ効果があります。
ケース3:アニメーションやUIの制御
スライダーや画像のフェードイン、スクロール制御などでは、たとえば画像を1秒ごとに順番に表示など一定の間隔で動作を遅らせると、より自然な動きが実現可能です。
2.JavaScriptでsleepを実行する方法
JavaScriptには標準のsleep関数が存在しないため、処理を一時的に停止させたり遅らせたい場合には、他の方法で実装しなければなりません。
おすすめは、JavaScriptの非同期処理の仕組みを活かして、指定した時間だけ処理を遅らせる方法です。
JavaScriptでsleepをsetTimeoutを使用して実行する
JavaScriptでsleep処理を実装する方法として、setTimeout関数を使用する方法があります。setTimeout()は指定した時間が経過した後に関数を実行します。
setTimeout()の構文は次の通りです。
setTimeout(実行する関数, 遅延時間[ミリ秒]); |
ミリ秒単位で指定できるため、1000ミリ秒(1秒)や200ミリ秒(0.2秒)といった細かい制御が可能です。
たとえば、setTimeoutを利用して3秒後にメッセージをコンソール表示するコードは次の通りです。
console.log("処理開始");
console.log("3秒後に実行される処理"); }, 3000);
|
このコードでは、setTimeout()の第2引数に3000を指定しています。3000ミリ秒つまり3秒後に「3秒後に実行される処理」というメッセージを表示します。ただし、厳密にはsleepのように一時停止しているわけではなく、指定した時間が経過したら実行する仕組みとなっています。
JavaScriptでsleepをPromiseを使用して実行する
setTimeoutはsleep関数のような機能として使えますが、Promiseを使っても似たような機能を実装可能です。
Promiseを使用したsleep関数のコード例は次の通りです。
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } |
この関数では、setTimeout()の完了後にresolve()が呼ばれ、Promiseが処理される仕組みです。
このsleep関数を使用した例として、3秒待機したあとに「完了」と表示するコードを紹介します。
console.log("処理開始");
console.log("3秒後に完了"); });
|
Promiseを使うと、.then()で次の処理をつなげることができるため、非同期処理との組み合わせがしやすくなります。
JavaScriptでsleepをasync/awaitを使用して実行する
async/awaitは、JavaScriptの非同期処理を同期的に記述できる構文です。Promiseとasync/awaitを組み合わせることで、さらにわかりやすくsleep機能を実装可能です。
async function example() { console.log("処理開始");
await sleep(3000); // 3秒待機
} |
awaitはPromiseの完了を待機する仕組みなので、処理が一時停止したかのようにコードを書くことができます。
さらにasync/awaitを応用すると、ループ処理やAPI呼び出しの間隔制御がわかりやすくシンプルに書けます。
コード例:1秒間隔で5回データを取得する
async function fetchDataWithDelay() { for (let i = 0; i < 5; i++) { console.log(`データ${i}を取得中...`); await sleep(1000); // 1秒待機 } } |
JavaScriptでsleepをミリ秒の指定をして実行する
これまでのコード例で紹介した通り、JavaScriptのsetTimeout、Promise、async/awaitでは、ミリ秒単位で時間を指定しなければいけません。たとえば、1秒であれば「1000」、0.5秒であれば「500」を指定してください。
ミリ秒単位で細かく制御すると、APIのrate limit回避やアニメーション制御にも役立てることができるでしょう。
JavaScriptでsleep処理を1行で書く方法
よりシンプルなコードでsleep処理を実装したい場合には、1行のコードで実現することもできます。
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); |
const sleep = (ms) =>
この部分は、JavaScriptのアロー関数で「sleep」という名前の関数を定義しています。引数の「ms」には、待機する時間(ミリ秒単位)を渡しましょう。
new Promise(resolve => setTimeout(resolve, ms))
この部分では、Promiseをnewしています。
setTimeout(resolve, ms)
この部分では、setTimeout関数を使って指定したミリ秒後にresolve関数を実行します。resolveが呼ばれることでPromiseが処理され、次の処理が実行されます。
このコードを活用してsleep機能を実装してみると次のようになります。
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
console.log("処理開始");
}
|
3.JavaScriptにおけるsleepの応用
JavaScriptでsleep処理が使用できると、さまざまなケースに応用できます。ここではsleep処理の応用パターンを具体的なコード例とともに解説します。
ループ処理時の間隔制御
JavaScriptでループ処理を行うと、短時間に膨大な処理を実行してCPU負荷が上がる可能性があります。sleep処理を入れることで、一定時間のインターバルを設けて負荷を抑えることができるため、ブラウザのフリーズを防ぐことが可能です。
コード例:ループ内で100ミリ秒の間隔を開けながら処理を5回実行する例です。
async function loopWithSleep() { for (let i = 0; i < 5; i++) { console.log(`処理 ${i + 1} 開始`); await sleep(100); // 100ミリ秒待機 console.log(`処理 ${i + 1} 完了`); } } loopWithSleep(); |
APIを連続で呼び出す場合の「rate limit」超過の回避
APIを連続して呼び出すと、サーバー側で「rate limit」の制限に引っかかる恐れが出てきます。sleep処理を挟むことで、API呼び出しの間隔を調整しrate limit超過を回避可能です。SNSやクラウドAPIなど、rate limitが厳しいサービスを使う場合はぜひ考慮してください。
コード例:fetch()を1秒間隔で5回実行
async function fetchDataWithDelay() { for (let i = 0; i < 5; i++) { const response = await fetch(`https://example.com/data/${i}`); const data = await response.json(); console.log(data);
// 1秒間隔でAPI呼び出し await sleep(1000); } } fetchDataWithDelay(); |
アニメーションやUIの制御
UI制御やアニメーションでは、requestAnimationFrameを使用したタイミング制御が重要です。sleep処理を加えることで、スムーズなアニメーションや、クリック・スクロールへの応答制御が可能になるでしょう。
requestAnimationFrameを使用し、ブラウザの再描画タイミングに合わせて実行できると、カクつきのないスムーズな動きを実現できます。
コード例:ボックスを1秒ごとに右へ移動させる
async function animateBox(box) { for (let i = 0; i < 10; i++) { box.style.transform = `translateX(${i * 10}px)`; await sleep(1000); } }
animateBox(box); |
JavaScriptでsleepを同期処理として実装する方法
JavaScriptでは、通常setTimeoutやPromiseを使用した処理は非同期で実行されます。しかし、async/awaitを使うとあたかも同期処理のように記述することが可能です。
コード例:2秒間処理を停止してから次の処理を実行
async function syncExample() { console.log("処理開始");
await sleep(2000); // 2秒待機
console.log("処理終了"); }
|
このコードでは、「await sleep(2000)」があるので、Promiseが解決されるまで待機します。Promiseが解決された後に次のconsole.logが実行されるため、同期処理のように処理が進みます。
async/awaitを使えば、処理を一時停止させて完了後に次の処理を行うコードをシンプルに記述可能です。実際にはJavaScriptは非同期で動作していますが、コード上では同期的な流れになるため、読みやすく管理しやすくなります。
JavaScriptで一時停止処理を実装する方法
一定時間処理を停止する処理を実装するにも、async/awaitとsleep関数を使用しましょう。
次のコード例では、1秒間隔で3回処理しますが、実際は処理の間で1000ミリ秒(1秒間)の一時停止を挟んでいます。
async function pauseExample() { for (let i = 0; i < 3; i++) { console.log(`データ${i + 1}取得中...`); await sleep(1000); // 1秒待機 } }
|
jQueryでsleepを実現する方法
jQueryにも標準のsleep関数はありませんが、$.Deferred() を使用すれば実現可能です。
コード例:jQueryを使用したsleep関数の実装
function sleep(ms) { var d = $.Deferred(); setTimeout(d.resolve, ms); return d.promise(); } |
$.Deferred()を使用し、1000ミリ秒(1秒)間隔で処理を行うコード例です。
$(function() { console.log("開始");
console.log("1秒経過"); });
console.log("2秒経過"); }); }); |
4.node.jsでsleepを実現する方法
JavaScriptはブラウザだけでなくNode.js環境でも使用できます。Node.jsにもsetTimeout()があるので、Promiseやasync/awaitを使用したsleep関数をそのまま仕様可能です。
一方でNode.js特有の注意点や最適化ポイントがあるため注意してください。
setTimeoutを使用したNode.jsでのsleep処理
Node.js環境でも、setTimeoutを使ったsleep関数は基本的にブラウザと同じ動作になります。
次のコードは、Node.jsでsetTimeoutを使ったsleep関数の例です。
console.log("処理開始");
console.log("1秒後に実行"); }, 1000);
|
Promiseとasync/awaitを使用したNode.jsでのsleep処理
Promiseとasync/awaitを使用すると、Node.jsでもシンプルなsleep処理が実装可能です。
Node.jsでもPromiseベースのsleep関数は次のように記述します。
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } |
この関数を利用して、async/awaitで同期処理のようにsleepを処理可能です。
コード例:async/awaitを使ったNode.jsでのsleep処理
async function example() { console.log("処理開始");
await sleep(2000); // 2秒待機
console.log("2秒後に実行"); }
|
Promiseとasync/awaitを使うと、非同期処理を意識しなくても同期処理のように記述でき、Node.js環境でもブラウザと同じように動作します。
5.JavaScriptでsleepを使用する場合のトラブルシューティング
JavaScriptでsleepを使った処理が正しく動作しないケースやタイミングがずれるケースがあります。setTimeoutやPromise、async/awaitを使用する場合、JavaScriptのイベントループやコールスタックの仕組みによって意図しない動作が発生する恐れがあるのです。
ここでは、sleep処理に関連する代表的なトラブルとその原因・解決方法を解説します。
setTimeoutが実行されない原因
setTimeoutを使ったsleep処理が期待どおりに動かない場合、イベントループやコールスタックに原因があるおそれがあります。
イベントループのブロック
JavaScriptはシングルスレッドで動作していますが、イベントループを利用して非同期処理を制御しています。setTimeoutを使用する場合、他の処理がイベントループをブロックしていると、setTimeoutの処理が遅延するおそれがあります。
重い計算処理がイベントループをブロックするケース
console.log("処理開始");
console.log("1秒後に実行"); }, 1000);
|
このコードでは、setTimeoutは1秒後に実行されるはずですが、forループでCPUに高負荷がかかるため、setTimeoutの処理が遅れます。そのためイベントループがブロックされてしまいます。
解決策としては、重い処理をsetTimeout()で分割して実行してみてはいかがでしょうか。イベントループがブロックされることなく、非同期で処理を分割できるようになるはずです。
function heavyTask() { for (let i = 0; i < 1e7; i++) {} console.log("部分処理完了"); setTimeout(heavyTask, 0); // イベントループに戻して再実行 }
|
コールスタックの問題
JavaScriptではコールスタックがオーバーフローすると、setTimeoutの実行タイミングが遅れる場合があります。
無限再帰によるコールスタックのオーバーフローするケース
function recursive() { console.log("再帰呼び出し"); recursive(); }
console.log("1秒後に実行"); }, 1000);
|
無限再帰によりコールスタックがオーバーフローしてしまうと、setTimeoutが実行されません。解決策としては、再帰呼び出しの間にイベントループを入れ、コールスタックのオーバーフローを回避しましょう。
function recursive() { console.log("再帰呼び出し"); setTimeout(recursive, 0); // イベントループを介在 }
console.log("1秒後に実行"); }, 1000);
|
async/awaitが効かないケース
async/awaitを使用したsleep関数が期待通りに動作しない場合、Promiseの未解決や非同期関数内でのミスが原因となっているかもしれません。
非同期関数内でPromiseが正しく動作しない場合
async/awaitを使用している場合、Promiseが正しく解決されないとawaitが待機状態のまま停止します。
Promiseが解決しないケース
async function brokenSleep(ms) { // resolveを呼んでいないため、Promiseが未解決のまま new Promise(() => setTimeout(() => {}, ms)); }
console.log("処理開始"); await brokenSleep(1000); // ここで処理が止まったままになる console.log("処理終了"); }
|
このコードでは、Promiseが解決されないため、awaitが無限に待機してしまいます。
Promise内でresolve()を呼び出し、正しく動作させましょう。
解決例
async function fixedSleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
console.log("処理開始"); await fixedSleep(1000); // 1秒待機 console.log("処理終了"); }
|
async/awaitの関数がPromiseを返していないケース
async/awaitを使用する関数は、必ずPromiseを返す必要があります。しかしPromiseを返せていない場合、awaitしても次の処理に進まないことがあります。
Promiseを返せていないケース
async function wrongExample() { setTimeout(() => console.log("実行完了"), 1000); }
console.log("開始"); await wrongExample(); // Promiseを返していないため待機が無効 console.log("終了"); }
|
Promiseを返すように修正してください。
async function correctExample() { return new Promise(resolve => { setTimeout(() => { console.log("実行完了"); resolve(); }, 1000); }); }
console.log("開始"); await correctExample(); // Promiseを返しているため正常に動作 console.log("終了"); }
|
6.まとめ
この記事では、JavaScriptに標準のsleep関数が存在しない理由と、その代替方法について解説しました。JavaScriptはシングルスレッドで動作するため、処理を完全に停止させるsleep関数は存在しませんが、setTimeout、Promise、async/awaitを活用すれば、sleep処理を実現可能です。
特に、async/awaitを使用したsleep処理は、同期処理のようにシンプルに記述できるため、API呼び出しやUI制御、アニメーション制御など、実務において役立ちます。
JavaScriptでのsleep処理を理解すれば、APIのrate limit回避や、UI・アニメーション制御のパフォーマンス向上につながります。ぜひ、この記事で学んだ知識を活用して、より効果的なJavaScriptコーディングに役立ててください。
本記事が皆様にとって少しでもお役に立てますと幸いです。
「フリーランスボード」は、数多くのフリーランスエージェントが掲載するITフリーランスエンジニア・ITフリーランス向けの案件・求人を一括検索できるサイトです。
開発環境、職種、単価、稼働形態、稼働日数など様々な条件から、あなたに最適なフリーランス案件・求人を簡単に見つけることができます。
単価アップを目指す方や、自分の得意なスキルを活かせる案件に参画したい方は、ぜひ「フリーランスボード」をご利用ください。