複数の非同期通信をする場合
適当に作るとこんな感じ。※変数宣言などアンチパターンなのはご愛嬌
var request = [
{ url: 'hoge00.json', params: { hoge: 123, huga: 456 } },
{ url: 'hoge01.json', params: { hoge: 246, huga: 912 } },
{ url: 'hoge02.json', params: { hoge: 369, huga: 1368 } },
{ url: 'hoge03.json', params: { hoge: 492, huga: 1824 } },
{ url: 'hoge04.json', params: { hoge: 615, huga: 2280 } }
];
var results = [];
var doneCount = 0;
for (var i = 0; i <= request.length; i++) {
$.ajax({
url: request[i].url,
data: request[i].params,
type: 'POST',
dataType: 'json',
success: function (responce) {
results.push(responce);
doneCount++;
if (doneCount === resqest.length) {
allDone();
}
}
});
}
function allDone () {
results; // => 結果の順番は通信が成功した順番
};
配列request
に格納したURLの順番と結果の順番は同じとは限らない。
初心者がよくハマるポイントだけど、ほぼ一斉に非同期通信を行い($.ajaxメソッドを実行し)、通信が成功した順番にsuccess
コールバックが実行されるので、その成功した結果の順番にresults
がプッシュされるからである。
こんな感じにできたら理想的
var request = [
{ url: 'hoge00.json', params: { hoge: 123, huga: 456 } },
{ url: 'hoge01.json', params: { hoge: 246, huga: 912 } },
{ url: 'hoge02.json', params: { hoge: 369, huga: 1368 } },
{ url: 'hoge03.json', params: { hoge: 492, huga: 1824 } },
{ url: 'hoge04.json', params: { hoge: 615, huga: 2280 } }
];
var jqXHR = $.multiAjax({
request: request,
type: 'POST',
dataType: 'json'
});
jqXHR.done(function (responce) {
responce; // => [00の結果, 01の結果, 02の結果, 03の結果, 04の結果]
});
上記を実現するには
直列処理ならば...
リクエストをひとつひとつ処理していく方法は、結構いろんなところで紹介されている。
基本的にはひとつずつAjax通信をして、そのコールバックで次のAjax通信を行なっている。もしくはasync
をfalse
にして、非同期通信でなく完全な同期通信をしてしまう方法。これなら結果の順番は絶対変わらない。
でも、やりたいのはそうじゃなくて、通信を同時に一気に行いたい。通信時間短縮のためには『並列』というのが大事。それに加えて結果の順番も保証してほしい。
$.whenを使えば意外と簡単に実現できる。
var request = [
{ url: 'hoge00.json', params: { hoge: 123, huga: 456 } },
{ url: 'hoge01.json', params: { hoge: 246, huga: 912 } },
{ url: 'hoge02.json', params: { hoge: 369, huga: 1368 } },
{ url: 'hoge03.json', params: { hoge: 492, huga: 1824 } },
{ url: 'hoge04.json', params: { hoge: 615, huga: 2280 } }
];
var jqXHRList = [];
for (var i = 0; i <= request.length; i++) {
jqXHRList.push($.ajax({ // $.ajaxの戻り値を配列に格納
url: request[i].url,
data: request[i].params,
type: 'POST',
dataType: 'json'
}));
}
// $.when関数を利用する
// $.whenは可変長引数を取るので、apllyメソッドを利用して配列で渡せるようにする
// $.whenのコンテキスト(applyの第一引数)はjQueryである必要があるので $ を渡す
$.when.apply($, jqXHRList).done(function () {
var json = [];
var statuses = [];
var jqXHRResultList = [];
// 結果は仮引数に可変長で入る **順番は保証されている**
// 取り出すには arguments から取り出す
// さらにそれぞれには [data, textStatus, jqXHR] の配列になっている
for (var i = 0; i < arguments.length; i++) {
var result = arguments[i];
json.push(result[0]);
statuses.push(result[1]);
jqXHRResultList.push(result[3]);
}
json;// => リクエストの配列と同じ順番で結果を参照できる
});
こんなロジックで、先に記した理想に沿ったプラグインにするなど、いろいろ作ればいい。
要するに$.when.apply
便利
Ajaxに限らずアニメーションなども、このテクニックを使えば並列の処理が行える。
読み込む外部ファイルやアニメーション要素の数が動的に変化する場合、$.when
のまま使うと可変長引数で渡すときに戸惑うが、apply
を使えば第一引数にさえ気をつければ簡単だ。ついでに結果は順番が保証されている。
仕様上の注意
配列の中身が一個だと結果が配列でなくなるので注意
$.when.apply($, [req, req, req]).done(function () {
arguments; // => [[data, status, jqXHR], [data, status, jqXHR], [data, status, jqXHR]]
});
$.when.apply($, [req]).done(function () {
arguments; // => [data, status, jqXHR]
});
なんともありがた迷惑な仕様…。配列の個数が1以下になる可能性がある場合は適切な処置が必要。
$.when.apply
を積極的につかってみよう!