jQuery.ajax()の非同期通信で実行順序を保証する方法
jQuery.ajax()の非同期通信で実行順序を保証する方法を紹介します。
具体的には、jQuery.ajax()による非同期通信を連続して実行する場合やjQuery.ajax()メソッドによる非同期通信と他の処理を続けて実行する場合、お互いの実行順序を保証する方法です。
本エントリーではjQuery1.8を使って解説します。その関係で、done()メソッドを使っています。done()がサポートされていないバージョンであればsuccess()に読み替えてください。
1.jQuery.ajax()の仕様
「仕様」という表現は適切でないかもしれませんが、例えばjQuery.ajax()による非同期通信を連続実行した場合、実行結果の順序は不定です。
簡単なサンプルとして、for文の中でjQuery.ajax()を実行するコードを用意しました。
<meta charset="utf-8" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<script>
var list = new Array('test1.html', 'test2.html', 'test3.html');
for (i=0; i<3; i++) {
var url = list.shift();
$.ajax({
url: url,
}).done(function(html) {
console.log(html);
});
}
</script>
test1.html~test3.htmlには、それぞれ「test1」「test2」「test3」という文字列が設定されています。
このコードを実行すると、成功時に起動されるdone()メソッド内に記述したconsole.log()の出力は、期待した順序(test1→test2→test3)になりません。
Firebugで確認したところ、console.log()の出力結果は次のようになるケースがありました。
上のサンプルはjQuery.ajax()同士の実行順序ですが、jQuery.ajax()と他の処理についても同様です。
次のサンプルでは、一番下のconsole.log()が先に実行される場合があります。というか、ほぼ先に実行されます。
<meta charset="utf-8" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<script>
$.ajax({
url: 'test1.html',
}).done(function(html) {
console.log(html);
});
console.log("foo");
</script>
2項および3項に非同期通信で実行順序を保証する方法を示します。
2.done()メソッド/always()メソッドを利用する
1項のサンプルで、実行結果をtest1.html、test2.html、test3.htmlの順で保証したい場合、done()メソッドまたはalways()メソッドから再帰的にjQuery.ajax()を呼び出すようにすればOKです。
<meta charset="utf-8" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<script>
var list = new Array('test1.html', 'test2.html', 'test3.html');
var foo = function(){
var url = list.shift();
$.ajax({
url: url
}).done(function(html) {
console.log(html);
if (list.length) {
foo();
}
});
};
foo();
</script>
もっとエレガントな実装があると思いますが、ここではjQuery.ajax()を関数fooでラップし、done()メソッドから関数fooを再帰呼び出しするようにしています。
Firebugで確認したconsole.log()の出力結果は期待通りになります。
1項の2つめのサンプルについても、次のようにdone()メソッドにconsole.log()を移動すれば解決します。
<meta charset="utf-8" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<script>
$.ajax({
url: 'test1.html',
}).done(function(html) {
console.log(html);
console.log("foo");
});
</script>
3.asyncオプションを利用する
jQuery.ajax()ではオプションとして「async」が用意されていて、「false」を設定すると同期通信が行えるようになっています。
したがって、冒頭のサンプルを次のようにすれば実行順序を保証することができます。
<meta charset="utf-8" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<script>
var list = new Array('test1.html', 'test2.html', 'test3.html');
for (i=0; i<3; i++) {
var url = list.shift();
$.ajax({
url: url,
async: false
}).done(function(html) {
console.log(html);
});
}
</script>
なお、asyncオプションとDeferredオブジェクトの併用について、1.8では非推奨になっており、「コールバック関数(complete/success/error)を利用すること」となっているようです。
言い換えると、Deferredオブジェクトの併用でなければasyncオプションは利用可能と思われます(間違っていたらすいません)。
4.参考サイト
参考サイトは以下です。ありがとうございました。
- jQuery+ajaxでモーダルのコンテンツを取得する方法
- jQueryでパスワードの表示・非表示を切り替えるサンプル
- jQueryでファイル選択時にプレビュー表示する方法
- ラジオボタンをjQueryで解除する方法
- テーブルのセルをポイントすると行と列を反転表示するjQueryプラグイン「Table Hover」
- jQueryで親ページからiframeのスクロールバーを非表示にする方法
- jQueryのカスタムビルドが簡単にできるサービス「jQuery Builder」
- jQueryでCSSをまとめて書き換える方法のまとめ
- 親ページからiframe内の要素にCSSを適用させる方法
- jQueryで要素を削除する方法のまとめ
- jQueryでテキストを追加するたびにスクロールさせる方法
- jQuery.ajax()でファイルをアップロードする方法
- preventDefault()で無効にしたイベントを有効にする方法
- jQueryで要素数を取得する方法のまとめ
- jQueryやJavaScriptでパスワードフィールドの文字を表示する方法