結果の順番を保証して、且つ『並列』でAjax通信を行う方法

## 複数の非同期通信をする場合

適当に作るとこんな感じ。※変数宣言などアンチパターンなのはご愛嬌

```js:
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`がプッシュされるからである。

## こんな感じにできたら理想的

```js:
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の結果]
});
```

## 上記を実現するには

### 直列処理ならば...

リクエストをひとつひとつ処理していく方法は、結構いろんなところで紹介されている。

- [jQueryでajax：非同期通信時、実行順番を保障する方法](http://kinopyo.com/blog/jquery-ajax-get-order-guranteed-async-transfer/)
- [jQuery.ajax()の非同期通信で実行順序を保証する方法](http://www.koikikukan.com/archives/2012/10/11-000300.php)

基本的にはひとつずつAjax通信をして、そのコールバックで次のAjax通信を行なっている。もしくは`async`を`false`にして、非同期通信でなく完全な同期通信をしてしまう方法。これなら結果の順番は絶対変わらない。

でも、やりたいのはそうじゃなくて、通信を同時に一気に行いたい。通信時間短縮のためには『並列』というのが大事。それに加えて結果の順番も保証してほしい。

### $.whenを使えば意外と簡単に実現できる。

```js:
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`を使えば第一引数にさえ気をつければ簡単だ。ついでに結果は順番が保証されている。

## 仕様上の注意

配列の中身が一個だと結果が配列でなくなるので注意

```js:
$.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`を積極的につかってみよう！