本ページはプロモーションが含まれています。 javascript

[javascriptでsleep処理]一行コピペコード 仕組みから理解できる構文解析!

2023年1月12日

javascriptでsleepをする方法。

javascriptでは、処理(スレッド)を一時停止させるsleep関数が存在しません

他の言語では珍しくない処理ですが、自分で組む必要があります。

今回は実装例とその解説を掲載しました。

また、すぐに使えるコードも用意しています。

とにかく今すぐ使いたい方はそのままご利用ください。

短縮コードに慣れていないと読みづらい可能性があります。

ですが比較と分解をしながら解説をしていますので、ご安心ください。

特に参考にしてほしい方

  • javascriptでsleepを今すぐに使いたい方
  • sleep処理の実装方法を知りたい方
  • 何度も調べなおさないよう、一発で理解したい方にもおすすめ!

注意ポイント

ES2017以降が対象です。

例によってIEでは動きません。

しかし、windows系でもWindowsServer以外ではサポートが切れています。

ほとんどの場合は、問題になることはないでしょう。

すぐに使いたい方へ!コピペで実装できるサンプルコード!


// 関数
const my_sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

// 呼び出しサンプル
await my_sleep(3000);

非同期処理「Promise」の基本をコードを使って解説

メインの関数では、Promiseという非同期処理を定義しています。

宣言だけでは秒数がずれてしまうので、呼び出し側で同期が必要です。

コードでいう「await」が、Promiseに対する同期命令になります。

動作自体は、ループで待機させてもあまり変わりません。

しかし、ループに比べ待機中のcpu消費を小さくできます。

また、「await」は非同期関数内でしか使用できません。

以下のコードを参考にしてください。


 const test = async () => {
    await my_sleep(3000);
  };
  test();

「test」という関数名の前に、「async」とあります。

この「async」が非同期関数の宣言方法です。

非同期処理は、非同期関数のみでしか使用できません

思わぬエラーを招くので、結構重要なルールです。

実際にサンプルプログラムを使って、動作を確認してみました。


/**
 * ※本筋とは無関係, 経過時間を[ms]で取得
 */
const get_time = () => {
  return new Date();
};

const my_sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

const test = async () => {
  const before = get_time();
  await my_sleep(3000);
  console.log({ type: 'シンプルawait版', diff: get_time() - before });
};
test();

画像はChromeのコンソールをキャプチャしたものです。

単位はミリ秒なので、約三秒間経過している事が分かります。

正確には「3000」ミリ秒なので、多少ずれていますね。

タイマーの誤差や出力までのラグがあるため、ぴったりにはならない可能性があります。

短縮コードを分解して、コードを意味を理解しよう

コードを分解して詳細を理解する。

上のコードには短縮テクニックが豊富です。

慣れていない場合は、なんとなく分かる程度の理解かもしれません。

理解をより深めるため、コードを分解していきましょう。

ラムダ式(アロー関数)のテクニックについて

今回は、まず先にテストコードの全体像を掲載します。


/**
 * ※本筋とは無関係, 経過時間を[ms]で取得
 */
const get_time = () => {
  return new Date();
};

const my_sleep = (ms) => {
  return new Promise((resolve) =>
    setTimeout(() => {
      resolve();
    }, ms)
  );
};

const test = async () => {
  const b = get_time();
  await my_sleep(3000);
  console.log({ type: "await 冗長版", distance: get_time() - b });
};
test();

ラムダ式(アロー関数)がどう使われているかを理解しよう!


const my_sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

このアロー関数から、中括弧を外してみます。


const my_sleep = (ms) => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

見慣れた構文に近づいてきました。
アロー関数には、次のような特徴があります。

一行で完了する処理は、中括弧とreturn文を省略することができる。

もちろん、アロー関数を使わず通常の関数で書くこともできます。


const my_sleep = function (ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
};

ここまでは、アロー関数に着目して解説してきました。

実はもう一つ、Promiseのタイマー処理に関して工夫されています。

次のセクションでは、Promiseの工夫について理解を深めましょう。

Promiseのテクニックについて

今回も元のコードと比較してみましょう。


new Promise(resolve => setTimeout(resolve, ms));

これは以下のように解釈できます。


new Promise((resolve) =>
  setTimeout(() => {
    resolve();
  }, ms)
);

まずPromiseは、引数としてresolve, rejectの2つの引数を取ります。

※今回使っているものは、エラーハンドルが不要なためresolveのみで構いません。

ここでは、次のような処理が行われています。

  1. Promiseのコールバックで、setTimeoutを呼び出し
  2. setTimeoutのコールバックで、resolveの通知を出す

そのため、下記のような構文は間違いです。

間違い1 resolveを呼んでいない => Promiseが解決(完了)していないとみなされる

new Promise((resolve) =>
  setTimeout(() => null, ms)
);

=> 出力なし

間違い2 setTimeoutでresolveを直接実行させてしまう

// 主に短縮版で注意
new Promise(resolve => setTimeout(resolve(), ms));

 

すぐに関数が実行されてしまいawaitが効きません。

async, awaitを使わない場合はPromiseの基本に立ち返ろう

Promiseで同期する場合は、async関数内でなければならないことは確認しました。

では何らかの制約でasyncを使えない場合は、どうすればいいでしょうか。

その時は、Promiseの「then」メソッドを使います。

構文としては、jQueryのAjaxに近いです。

使ったことがあれば、イメージしやすいのではないでしょうか。


// 呼び出し側を変更
my_sleep(3000).then(() => {
  console.log({ type: "callback版", distance: get_time() - b });
});

処理の流れ

Promiseの戻り値に対して、メソッドチェーンで繋いでthen()を定義します。

最初の引数に、Promiseがresolveを通知した際のコールバックを渡しましょう。

この方法では、ネストが深くなりがちです。

awaitが使える場面では、基本的に採用することをおすすめします。

そもそもjavascriptでsleepは必要なのか

javascriptでスリープを使う場面とは?

標準で提供されていない以上、積極的に使う場面はないと思います。

async, await, そしてコールバックがあればなんとかなるものです。

可能性があるとすれば、外部APIと連携する時などでしょうか。

外部API連携の使用例

更新処理が絡む場合は、「リクエスト処理中」で返す場合も多いです。

実際にCMSのRESTAPIで経験したことがあります。

1ページにつき10秒かかるなら、10~15秒くらいインターバルをとればOKです。

※実際はネットワークやAPIサーバー次第で、振れ幅があります。

sleepは簡単なものの、実用性としてはイマイチです。

本番では、setTimeoutなどを使いながらfetchAPIを叩いた方が確実でしょうね。

[まとめ]javascriptでsleep機能は結構簡単に作れる

ES2017以降の機能を使えば、結構簡単に実装できることが確認できたと思います。

一方でラムダ式やPromiseを駆使しているなど、思ったより?高度なことをしています。
ES2015の浸透が遅れたのはIEのせいです。

javascriptで遅延動作をさせるときは、

  1. 同期処理(async, await)で完了を受け取れないか検討する
  2. コールバックで解決できないか検討する
  3. それでもダメならsleepで対処する

くらいの優先度が良いと思います。

参考

Promise
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise

アロー関数(ラムダ式)
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions

おすすめ記事をCHECK!

aptがあればapt-getは不要? 1

Debian系のパッケージ管理として「apt」が登場してから、時々「apt-getは不要!」という話を聞くことがあります。 結論から言うと、公式では「使い分けよう」が正解です。 公式の方では、次のよう …

2023年2月時点。新しくなったAWSシークレットキーの作り方。 2

AWSの管理画面は、結構頻繁に変わりますよね。 以前まではIAMとシークレットアクセスキーを同時に作成できましたが、今はその機能が見当たらなくなりました。 結論としては、IAMのユーザーを作成後に、設 …

初心者におすすめ! 失敗しないレンタルサーバー3選。 3

ある程度経験がないと、レンタルサーバーはどれも同じに見えるかもしれません。 しかし、選び方次第で、設定に2倍、3倍の時間がかかってしまうこともあります。 そこで今回は、コスパ・使いやすさに特化した3つ …

-javascript
-