one's way blog

ワクワクを生み出せるWebエンジニアを目指して。

【32:jQuery.Deferred】要素を順にアニメーション表示

f:id:seintoseiya:20150804211049p:plain
プロジェクトNo.32:jQuery.Deferred - DEMO

jQuery.Deferredはバージョン1.5から導入された、非同期処理をうまく扱うための標準モジュールです。
jQuery.Deferredなしで要素を順にアニメーション表示するにはコールバック関数とdelay()を使えばできるようですが、
ソースが乱雑になりスマートではありません。
jQuery.Deferredを使うことで1つ1つのアニメーションを関数化して扱いやすくなります。

下準備

アニメーションさせたい要素を準備

HTML
<div id="viewArea">
	<div class="box_red">1</div>
	<div class="box_green">2</div>
	<div class="box_blue">3</div>
	<div id="replay">Replay?</div>
</div>

アニメーションの関数を作成する

それぞれanimate関数などを使ってアニメーションを設定します。

JavaScript
function firstAction(){
    $(".box_red").animate({
        "top" : "400px"
    }, 1000);
}
function scoundAction(){     
    $(".box_green").animate({
        "top" : "450px"
        }, 1000);
}
function thirdAction(){
    $(".box_blue").animate({
        "top" : "300px"
        }, 1000);
}
function showReplay(){
    $("#replay").fadeIn("fast");
}

ただし、このままでは関数を1つずつ呼び出したとしても、
全て同じタイミング(前の処理の終了を待たず)で実行されます。
これがいわゆる非同期処理ですね。
それでは、順に実行するためにjQuery.Deferredを使って先程のソースを編集していきましょう。

Deferredオブジェクトの扱い方

やることは以下の通り。

  • 各関数内でDeferredオブジェクトを生成
  • アニメーションのコールバック関数でDeferredオブジェクトの実行可能状態にする(実際にはresolve()という関数を呼び出す)
  • 関数の最後でDeferredオブジェクト(の持つPromiseというオブジェクト)を返す(実際にはpromise()という関数を返す)
  • 各関数を呼び出す際にthen()という関数で繋げる
JavaScript
$(function() {
    function playAnimation(){
        // .then(関数名)で関数を繋げる
        firstAction()
            .then(scoundAction)
            .then(thirdAction)
            .then(showReplay);
    }
     
    function firstAction(){
        // Deferredオブジェクトを生成
        var d = new $.Deferred;
        $(".box_red").animate({
            "top" : "400px"
        }, 1000, function(){
            // 状態を実行可能にする
            d.resolve();
        });
        // Promiseオブジェクトを返す
        return d.promise();
    }

    function scoundAction(){
        var d = new $.Deferred;        
        $(".box_green").animate({
            "top" : "450px"
            }, 1000, function(){
            d.resolve();
        });
        return d.promise();
    }

    function thirdAction(){
        var d = new $.Deferred;
        $(".box_blue").animate({
            "top" : "300px"
            }, 1000, function(){
            d.resolve();
        });
        return d.promise();
    }

    function showReplay(){
        $("#replay").fadeIn("fast");
    }

    // 実行
    playAnimation();
});

その他の処理

後はリプレイボタン押下時の処理や、最初のアクションでの初期位置指定などをしておきます。

JavaScript
$("#replay").click(function(){
    $("#replay").fadeOut();
    playAnimation();
});

function firstAction(){
    var d = new $.Deferred;
    // 初期位置指定
    $(".box_red, .box_green").css({
        "top" : "-100px"
    });
    $(".box_blue").css({
        "top" : "-200px"
    });
    // アニメーション
    $(".box_red").animate({
        "top" : "400px"
    }, 1000, function(){
        d.resolve();
    });
    return d.promise();
}


今回は要素を順にアニメーション表示するという点にフォーカスを当ててみましたが、
最初でも記述しましたがjQuery.Deferredは非同期処理をうまく扱うための標準モジュールです。
他にもWebAPIを利用して、APIからの結果が返ってきた後に処理したい場合などでも活躍しそうですね。

また、今回はDeferredオブジェクトやPromiseオブジェクトなどの概念的な話には触れませんでしたが、
もし興味があるなら以下の記事が参考になるかと思います。

全ソースはこちら

github.com