JavaScriptでsleep関数を実装するやり方【Promise&await】

同期的なコードを書きたい場合・・・

PHPだったら sleep(10)  とかすれば 10秒間スリープできます。

でもJavaScriptでは、仕様的な理由でsleep関数が存在しません。

でも作り方がようやく分かったので、
ここでは JavaScriptで sleep関数を実装する方法&コード例 をまとめときます。

JSでのsleep関数作成に必要な3つの知識

まずsleep関数作成には次の3つの知識が必要

  • Promise
  • アロー関数
  • await  async

順にどのようなモノなのか、ざっくり説明していきます。

1.Promise(非同期通信を行うオブジェクト)

ではまず Promise について。

これは公式リファレンスだと、こういう説明がされてます。

Promise オブジェクトは非同期処理の最終的な完了処理(もしくは失敗)およびその結果の値を表現します。

引用元 : Promise - JavaScript | MDN

このPromise は fetch API でも使われていて、 then()  はPromise から受け継いだ感じらしいです。

そこらへんは詳しくないので、ここでは省略します。

 

たとえば 1.5秒後に非同期で何かするコードを書くなら、こういう感じです。

▼ とても簡単な Promise のコード例

上コードの resolve  が処理が正しく行われたときに実行したコールバック、
そして reject  が通信エラー時とかの失敗時に実行したいコールバック。

この非同期処理できる Promise が sleep関数実装の1つめのカギです。

2.アロー関数(functionの代替式的なの)

2つめは アロー関数 について

▼ アロー関数のMDNリファレンスでの説明

アロー関数式は、より短く記述できる、通常の function 式の代替構文です。また、this, arguments, super, new.target を束縛しません。アロー関数式は、メソッドでない関数に最適で、コンストラクタとして使うことはできません。

引用元 : アロー関数 - JavaScript | MDN

たとえば () => {}  は一番単純なアロー関数の例。

もちろん「通常の function 式の代替構文」なので、 function  による置き換えも可能です。

ただしアロー関数は次の利点があるので、使えると便利。

  • コードを function式 より短くできる
  • 変数をいちいち bind する手間がなくなる

スマートにコードを書くならコチラを使う方がいいかもしれません。

MDNリファレンスでも Promise の説明はアロー関数なので。

3.await async(同期・非同期の制御)

最後は await , async について。

これは関数定義の前につけ、動作を定義するためのキーワードです。

  • async
    これを関数の前につけると非同期関数(=他の処理を待たない)になる。
    たとえば async function hoge(){...}  みたいな感じ
  • await
    これは非同期関数の中で使い、それを使うとローカルスコープで処理をブロックする。
    たとえば await function fuga()  みたいな感じ

文字通り async = 「非同期」、 await = 「待つ」 という意味。

この2つが sleep関数の実装でかなり重要な役割をもってきます。

sleep関数を実装する手順&コード例

では具体的なsleep関数の実装手順について。

今紹介した Promise  と await  async  を使えば簡単にできます。

その手順は次の2ステップ

 

1.まずミリ秒まで待てる sleep関数 を作成

▼ こんな感じで sleep関数 作ってみた

アロー関数が分かりにくい場合は、普通の function式 でも代替可能です。

 

2.ウェイトしたい箇所を async で囲み、sleep関数実行

▼ 例えばコード内での書き方例

 

上コードを実行すると、1秒おきに 'sleep is done'  が表示されるはず

▼ 実際のコンソールの様子

実装したsleep関数で1秒おきにメッセージを表示させる例

同期的になるのは async  で囲った部分だけ。

だから sleep(1000)  の影響はその外には影響を及ぼしません。

 

ちなみに少し応用

次みたく 片方は500ミリ秒おき、もう片方は300ミリ秒おき みたいな処理もできます。

▼ 0.5秒 と 0.3秒 おきに2つのタスクを実行するコード例

上のコードを実行するとコンソールはこんな状態になるはず

作成したsleep関数を使い、0.5秒おきと0.3秒おきに別々のタスクを走らせている様子(※ 厳密にはマルチスレッドではない)

まるで他言語でのマルチスレッドみたいな感じ。

まあ JavaScript はシングルタスクなので、厳密にはスレッドとは言えないですが・・・

もし厳密にスレッド実装するなら Web Worker とか使うそうです。(詳しく知らない)

ついでに awati と async の互換性について(蛇足)

最後に蛇足だけど、互換性についての話を少しだけ

まず Promise  だと95%以上のブラウザに対応してるから問題なし。

でも await  と async  って対応ブラウザがどの程度多いのか気になりました。

 

そこで Can i Use を使って調べてみた結果がコチラ

▼ await のブラウザ互換性

▼ async のブラウザ互換性

簡単に互換性についてまとめると・・・

  • await  =>  2019/11/10 時点で 88.86% に対応、
  • async =>  2019/11/10 時点で 91.52% に対応

当然ながらIEでは未対応、また一部のモバイルブラウザでも未対応が多そう

でも最新ブラウザやAndroidやiPhoneに対応させる分には問題ないはず

ただし、【IEに何が何でも対応させたい】なら await  と async  は諦めないとダメかも
(日本はやたらとIEが好きだけど、使い続ける理由が良く分からない、、、)

JSでのsleep関数実装まとめ

ということで、実装方法の簡単なまとめ

  • Promise
    非同期処理用オブジェクトで、この中に setTimeout  とかでスリープさせる
  • awaitとasync
    非同期なコードを async  で囲み、 await sleep(1000)  のように呼び出せばOK

以上、JavaScriptで同期的に sleep させる方法でした。ではまた(^_^)/~

Commentsこの記事についたコメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください