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/