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

jQuery で AJAXするのに Deferred が便利ですよねーという話。
今回は jQuery.when() についてです。
複数の非同期処理を扱うとき
たとえば、
- JSONデータA を AJAX で取得したい
- 別のデータB も AJAX で取得したい
- 両方の取得が終わったら、続く処理をしたい
こういう処理を 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/


