JavaScriptプログラム

setTimeoutを用いて、非同期関数を同期的に動かす

JavaScriptやjQueryでプログラミングしていると、非同期関数を使用する箇所で、自分が意図しているのとは違う動きになることがあります。
その際、非同期関数を同期的に動かすことができれば、問題は解決します。

 

非同期関数(Asynchronous Function)

例えば、ボタンをクリックすることで、以下のことを順次実行したいとします。

  1.  テキストエリアをスライドアップ
  2.  テキストエリアに「10」と表示
  3.  テキストエリアをスライドダウン
  4.  テキストエリアに「20」と表示

 

単純にプログラムにすると、以下となります。

プログラム1
$(function(){
    $('#btn').on('click', function() {
        $("#textarea").slideUp(1000);     // 非同期関数
        $("#textarea").html('10');        //  同期関数
        $("#textarea").slideDown(1000);   // 非同期関数
        $("#textarea").html('20');        //  同期関数
    });
});

 

上記プログラムの中で、slideUp() とslideDown() が、非同期関数です。

 

(注)slideUp(1000)
スライドアップ(slideUP)は、要素を上方向にスライドして隠します。
数字の1000は、デュレーション(duration)で、スライド開始から完了までの時間です。
単位はm秒で、1000と書けば、1000m秒すなわち1秒となります。

(注)slideDown(1000)
スライドダウン(slideDown)は、隠れている要素を下方向にスライドして表示します。
数字の1000は、デュレーション(duration)です。

 

非同期処理

JavaScriptでは、プログラム中に非同期関数があると、その関数の終了を待たず次に進みます(非同期処理)。

例えば、プログラム1 の3行目と4行目では、スライドアップのデュレーション(1秒)を待たず、次に進み、テキストエリアに「10」を表示します。

 

そのため、このプログラム1 を動かすと、以下の順番で動作します。

  1.  テキストエリアに「10」を表示
  2.  テキストエリアに「20」を表示
  3.  テキストエリアをスライドアップ
  4.  テキストエリアをスライドダウン

この動作は、当初、意図したのとは違う動きになっています。

 

プログラム2

後の説明のため、プログラム1 を変形させています。
プログラム1 とプログラム2 の動作は同じです。

<!DOCTYPE html>
<html lang="jp">
    <head>
        <meta charset="utf-8">
        <title>Control Asynchronous Function Synchronously</title>
        <script src="../lib/jquery.min.js"></script>
        <script>
            var duration_A = 2000;
            var duration_C = 2000;

            $(function(){
                $('#btn').on('click', function() {
                    A();                // slideUp
                    B();                // 10
                    C();                // slideDown
                    D();                // 20
                });
            });

            function A() {
                $("#textarea").slideUp(duration_A);
            }

            function B() {
                $("#textarea").html('10');
            }

            function C() {
                $("#textarea").slideDown(duration_C);
            }

            function D() {
                $("#textarea").html('20');
            }
        </script>
    </head>
    <body>
        <input type="button" id="btn" value="Click"><br>
        <textarea id="textarea" cols="50" rows="10" readonly></textarea>
    </body>
</html>

 

プログラム2 の説明

グローバル変数

  • duration_A: スライドアップのデュレーション。 2秒に設定。
  • duration_C: スライドダウンのデュレーション。 2秒に設定。

 

 

setTimeoutを用いた同期処理

考え方

非同期処理
非同期関数A()の後に、同期関数B()があった場合、先にB()が動き、次にA()が動きます。

A();			// 非同期関数
B();			//  同期関数
  1.  同期関数B()を実行
  2. 非同期関数A()を実行

 

同期処理
非同期関数A()の処理時間はduration_Aなので、同期関数B()をduration_A後に動くようにします。

A();                            // 非同期関数
setTimeout( function() {
    B();                        //  同期関数
}, duration_A);

setTimeoutを用いることで、duration_A後にB() が動きます。

  1.  非同期関数A()を実行
  2.  duration_A後にB()を実行

 

プログラム3

プログラム2 の13-16行目を書き換えました。

<!DOCTYPE html>
<html lang="jp">
    <head>
        <meta charset="utf-8">
        <title>Control Asynchronous Function Synchronously</title>
        <script src="../lib/jquery.min.js"></script>
        <script>
            var duration_A = 2000;
            var duration_C = 2000;
		
            $(function(){
                $('#btn').on('click', function() {
                    A();					// Asynchro. Func.
                    setTimeout(function() {
                        B();					//  Synchro. Func.
                        C();					// Asynchro. Func.
                        setTimeout(function() {
                            D();				//  Synchro. Func.
                        }, duration_C);
                    }, duration_A);
                });
            });

            function A() {
                $("#textarea").slideUp(duration_A);
            }

            function B() {
                $("#textarea").html('10');
            }

            function C() {
                $("#textarea").slideDown(duration_C);
            }
		
            function D() {
                $("#textarea").html('20');
            }
        </script>
    </head>
    <body>
        <input type="button" id="btn" value="Click"><br>
        <textarea id="textarea" cols="50" rows="10" readonly></textarea>
    </body>
</html>

 

 

プログラム2 の説明

プログラム2 の、13行目~20行目を抜き出しました。 ここは、ボタンをクリックした後の処理です。

                $('#btn').on('click', function() {
                    A();					// Asynchro. Func.
                    setTimeout(function() {
                        B();					//  Synchro. Func.
                        C();					// Asynchro. Func.
                        setTimeout(function() {
                            D();				//  Synchro. Func.
                        }, duration_C);
                    }, duration_A);
                });

以下の順で、同期的にプログラムが動きます。

  1.  A()が動き始め、2秒後に動き終わる
  2.  B()が動く
  3.  C()が動き始め、2秒後に動き終わる
  4.  D()が動く

(注意)duration_A, duration_C の値は、共に2秒です。

コメントを残す

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