javascriptにおけるsleep,wait関数

javascriptで一定時間sleepする関数を使いたくなったので、その方法をメモしておきます。

やりたいこと

c言語で言う所のこういう処理をjavascriptでもやりたくなりました。

while (1) {
    if ( is_ready() ) break;
    usleep( 100000 ); // wait 100000us (100ms)
}
do_something();

非同期で何か別の処理が行われており、そちらの準備が整うまで待ってからdo_somithing()関数を実行したい。
という非常にシンプルなもの。

javascriptにsleep関数は、、、

ありません。
そもそもjavascriptの使い方って、onreadyとかonloadに関数をどんどん追加するとか、windowのサイズを測るとかに使うことが多いので、時間変化に伴って何かを行う処理というのはあまり想定されていないのです。
デザインの時間的変化はcssのtransitionを使えば良い話ですので。
まずは、あなたがその挙動を実現するために必要なのはsleep()関数なのかをしっかり考える必要があります。
それでもsleep()関数を使いたい。という時は、、、

setTimeout()関数で代用する。

javascriptでsleep()関数を実現するためには、setTimeout()という関数を用いて実現することができます。

setTimeout()関数

setTimeout()関数は、引数に指定した関数をnミリ秒後に実行することができる関数になります。使い方は以下の通りです。

Number setTimeout( function, milliseconds, param1, param2, … )

・返り値 Number
この関数は、数値が返り値にセットされています。この数値は、後述するclearTimeout()というsetTimeout()関数の実行予約を取り消す為に使います。

・function
関数オブジェクト。実行したい関数を渡します。必須の引数です。

・milliseconds
第一引数で渡した関数を何秒後に実行するかを指定します。単位は[ms](ミリセカンド、1/1000秒。)オプション引数で、デフォルト値は0。(引数を指定しなかった場合には、即時に第一引数で渡した関数を実行します。)

・param1, param2, …
第一引数にて指定した関数に渡すパラメータを指定します。
IE9以前のバージョンでは使用することができません。

setTimeout()関数の親戚、setInterval()関数
同じような動き方をする関数としてsetInterval()という関数もあります。setTimeout()関数では、引数に指定した関数をn病後に1度のみ実行する関数でしたが、この関数は引数に指定した関数をn秒毎に繰り返し実行します。

Number setInterval( function, milliseconds, param1, param2, … )

引数については、setTimeout()関数と同様です。

clearTimeout()関数

clearTimeout()関数は、先ほと説明したsetTimeout()関数での関数の実行予約を取り消す為に使用します。

clearTimeout( id )

・id
Nuber。このidにsetTimeout()関数の戻り値を入れることで、setTimeout()関数にて予約した関数の実行をキャンセルすることができる。

var id = setTimeout( some_function, 1000 ); // 1000ミリ秒後にsome_function()を実行
clearTimeout( id ); // キャンセル

この関数で、idに不正な値を入力ても、特に何も起こりません。(例外を投げません。)

setInterval()関数の実行をキャンセルする場合は、代わりにclearInterval()という関数を使います。使い方は、clearTimeout()関数と同様です。

sleep関数を作る

というか、setTimeout()関数があれば、sleep()関数は必要はないですね。

どこかの記事で、無理やりCPUをビジー状態にしてまでsleep()関数を作成しているサイトを見かけましたが、そんなことをせずとも、setTimeout()関数で待ちたい秒数と、待った後に実行したい関数を入れてあげれば良い話です。

サンプルコード

上の方で記述した「やりたいこと」のコードをこのsetTimeout()関数を用いて実現してみると、

function sample_func() {
    if ( !is_ready() ) {
        setTimeout( sample_func, 100 ); // wait 100ms and execute sample_func() again
        return;
    }
    do_something();
}
sample_func();

こんな感じになります。
肝となるのは、sample_func()の中で、setTimeout()関数を用いてsample_func()自身をもう一度呼び出している点ですね。

これで、is_ready()がtrueになるまで100ms間隔でsample_func()が呼び出されることになります。

先ほども紹介しましたが、setTimeout()関数の親戚として、setInterval()という引数に指定した関数を指定した秒数[ms]毎に繰り返し呼び出す関数もあるので、状況に応じて使い分けると良いでしょう。

あと、setTimeout()、setInterval()で予約した関数の実行をキャンセルする関数clearTimeout()、clearInterval()という関数もあることも、頭の片隅に入れておくと良いでしょう。

var id1 = setTimeout( some_function, 100 );
clearTimeout( id1 );
var id2 = setInterval( some_function, 100 );
clearInterval( id2 );

setTimeout(), setInterval()はclearのためのIDを戻り値として返してくれるので、
その値をclearTimeout(), clearInterval()関数の引数に放り込めば、予約した関数の実行をキャンセルすることができます。

ちょっと小言。

最近javascriptに触れる機会が増えてきたのだが、javascriptの関数でググるとしょうもないページがヒットすることが多いように感じる。

c++とかpythonとかの関数を検索する時は、関数名と引数の種類、戻り値といった情報が簡潔にまとめられたわかりやすいサイトに巡り会うことが多いのだが、javascriptとかjqueryではそうはいかない。
長ったらしい冗長な説明ばかりしてあって、肝心な部分が書いてなかったりする。
最悪なのは、「試しにやってみましたできました。」っていう報告の記事。
初歩的な関数が動きましたって言う報告は誰も聞きたくは無い。
そんな内容の薄い記事を検索上位に持ってくるgoogleさんサイドにも問題はあると思うのだけれども。
web系の記事に、もっとまともな記事が増えることを切に願っています。

こんなことを言っておいて、私が誰にとってもわかり易く簡潔な文章をかけているかと言われると、自身を持って首を縦には振れないのですがね。。。(笑)