jQuery:$.ajax()をforで回した時の順番

jQuery:$.ajax()をforで回した時の順番

author : koki

publish date :

いろんなJS案件に携わって行くと、稀にAjax通信を一度に複数回行う必要がでてくると思います。そういう案件のほとんどは、取ってきたAのデータはエリアAに表示、BはエリアBに表示・・・という感じにデータを入れていかないといけないのですが、Ajax通信はファイルのロード完了状況の関係でデータの返ってくる順番がバラバラで思い通りに扱えない時があると思います。

一つのAjax通信が終わってからもうひとつ読み込めばいいじゃん!って思うのですが、読み込むファイル数が多い場合はファイルの数×ロード時間となってしまい、読み込みに時間がかかってしまいそうなので並列で読み込みをさせようと思います。
ということで今回は、下記条件を満たすコードを紹介します。

  • 一度の動作で複数のデータにAjax通信する
  • 返ってきたデータは返却順にかかわらず、それぞれ所定の位置に表示させる
  • データは並列で読み込む

$.ajax()を読み込むファイルの数だけ書いて対応することはできるのですが、非常に長く、更新性の悪いスパゲッティコードになるのでアンチパターンとします

まずは一つのファイルにアクセスする$.ajax()のコードです。

通常の$.ajax()

jQuery(function($){
	var targetURL = 'test01.html';
	var xhr = $.ajax({
		url: targetURL,
		dataType: 'text',
		timeout: 30000
	});
	xhr.success(function(res){
		$('.test').html(res);
	});
	xhr.error(function(res){
		$('.test').eq(i).html('ファイルを読み込めませんでした。');
	});
	xhr.complete(function(res){});
});

このコードでは一つのファイルにアクセスするだけですので、次はforで囲い、連続でファイルを$.ajax()できるようにします。

とりあえずforで囲った$.ajax()

jQuery(function($){
	var targetURLArr = [
		'test01.html', 'test02.html', 'test03.html', 'test04.html', 'test05.html',
		'test06.html', 'test07.html', 'test08.html', 'test09.html', 'test10.html'
	];
	for(var i = 0, len = targetURLArr.length; i < len; i++){
		var targetURL = targetURLArr[i];
		var xhr = $.ajax({
			url: targetURL,
			dataType: 'text',
			timeout: 30000
		});
		xhr.success(function(res){
			$('.test').eq(i).html(res);
		});
		xhr.error(function(res){
			$('.test').eq(i).html('ファイルを読み込めませんでした。');
		});
		xhr.complete(function(res){});
	}
});

この方法ではデータが一切入りません。
原因を調べてみるとiが常に最大値となっていました。

正しく$.ajax()forで回すには$.ajax()を無名関数で囲い、その無名関数に変数iを渡さなければいけません。
文章の説明には限界があると思うので次のコードを見てみてください・・・

非同期通信で$.ajax()するコード

jQuery(function($){
	var targetURLArr = [
		'test01.html', 'test02.html', 'test03.html', 'test04.html', 'test05.html',
		'test06.html', 'test07.html', 'test08.html', 'test09.html', 'test10.html'
	];
	for(var i = 0, len = targetURLArr.length; i < len; i++){
		var forCount = i;
		(function(i){
			var targetURL = targetURLArr[i];
			$.ajax({
				type: 'GET',
				url: targetURL,
				dataType: 'text',
				timeout: 30000,
				success: function(res){
					$('.test').eq(i).html(res);
				},
				error: function(){
					$('.test').eq(i).html('ファイルを読み込めませんでした。');
				},
				complete: function(){}
			});
		})(forCount);
	}
});

無名関数(function(i){})(forCount);$.ajax()をくくる事によって、変数iに正しい数値が渡されます。

目的によって、同期通信のほうが良い場合もあると思うので、同期通信のサンプルコードも載せておきます。
同期通信はファイル数が少ない場合や、表示順を思い通りにしたい場合に有用だと思います。

$.ajax()のオプションでasync: falseとすれば同期通信となるので、ファイルのロード順が確約されます。

同期通信で$.ajax()するコード

jQuery(function($){
	var targetURLArr = [
		'test01.html', 'test02.html', 'test03.html', 'test04.html', 'test05.html',
		'test06.html', 'test07.html', 'test08.html', 'test09.html', 'test10.html'
	];
	for(var i = 0, len = targetURLArr.length; i < len; i++){
		var targetURL = targetURLArr[i];
		$.ajax({
			type: 'GET',
			url: targetURL,
			dataType: 'text',
			async: false,
			timeout: 30000,
			success: function(res){
				$('.test').eq(i).html(res);
			},
			error: function(){
				$('.test').eq(i).html('ファイルを読み込めませんでした。');
			},
			complete: function(){}
		});
	}
});

目的によって、非同期通信や同期通信をうまく使い分けましょう!