matsuo

jQuery.when() で、複数の非同期処理を扱う

jQuery で AJAXするのに Deferred が便利ですよねーという話。
今回は jQuery.when() についてです。

複数の非同期処理を扱うとき

たとえば、

  1. JSONデータA を AJAX で取得したい
  2. 別のデータB も AJAX で取得したい
  3. 両方の取得が終わったら、続く処理をしたい

こういう処理を Deferred の仕組みを使わないで書くと、こんな感じになりますでしょうか。

var data_a, data_b;

$.getJSON('a.json', function (data_a) {
    $.getJSON('b.json', function (data_b) {
        // 両方終わった時の処理
        console.log(data_a, data_b);
    });
});

Deferred を使わないと、コールバックの中に次のコールバックを書いて…… といった書き方です。まあまだ2段階くらいならいいんですが、処理が増えるにつれ、どんどんコードの階層が深くなってしまいます。

また、これ、データA 取得に5秒、データB 取得に5秒かかるとしたら、トータルで10秒かかってしまいますね。1つの処理が終わってから、次の処理に入るので。

できれば、非同期処理を順番に実行するんじゃなくて、並列に扱いたい。データAもデータBもいっぺんに取ってきてほしい。

jQuery の when() を使う

ということで jQuery.when() を使ってみた例です。
「複数の非同期処理が全部終わったら、続く処理を行う」というのがすっきり書けます。

$.when(
    $.getJSON('a.json'),
    $.getJSON('b.json')
)
.done(function(data_a, data_b) {
    // すべて成功した時の処理
    console.log(data_a, data_b);
})
.fail(function() {
    // エラーがあった時
    console.log('error');
});

こんな感じ。

when() の中には、いくつでも Deferred な処理を書けます。書いた処理がすべて成功したら done() に処理が渡り、どれか1つでもエラーになると fail() に処理が渡ります。

コールバックを使ったものよりもコードが見やすいですし、この先なにか機能追加等で起きる変更にも強そうな構造です。

他の Deferredな処理と組み合わせたサンプル

別のサンプルをひとつ。たとえば、
「JSONデータを取得してきたい、ただし、最低でも1秒間待たせてから、次の処理をしたい」
という場合のコード。

getJSON() と、「setTimeout() でn秒経過したら promise を返す deferred」とを組み合わせます。
when() からその2つを実行させ、両方とも終了したら done() に処理が渡る、という流れ。

// 指定された秒数だけ待つ deferred
function wait(sec) {
    var d = $.Deferred();
    setTimeout(function() {
        d.resolve();
    }, sec * 1000);
    return d.promise();
}

$.when(
    $.getJSON('sample.json'),
    wait(1) // 1秒待ってから成功を返す deferred
)
.done(function(data) {
    console.log(data);
});

こんな感じでしょうかー

参考

jQuery オフィシャルのマニュアル

jQuery.when() | jQuery API Documentation
http://api.jquery.com/jQuery.when/

Yahoo! Tech Blog のこちらの記事、Deferred 関連について めちゃくちゃ分かりやすかったです。

爆速でわかるjQuery.Deferred超入門 - Yahoo! JAPAN Tech Blog
http://techblog.yahoo.co.jp/programming/jquery-deferred/

お問い合わせはこちら