jQuery.ajax()の非同期通信で実行順序を保証する方法

jQuery.ajax()の非同期通信で実行順序を保証する方法

Posted at October 11,2012 12:03 AM
Tag:[Ajax, jQuery]

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()の出力結果は次のようになるケースがありました。

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()の出力結果は期待通りになります。

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.参考サイト

参考サイトは以下です。ありがとうございました。

関連記事
zenback
人気エントリー
トラックバックURL


コメントする
greeting

*必須

*必須(非表示)


ご質問のコメントの回答については、内容あるいは多忙の場合、1週間以上かかる場合があります。また、すべてのご質問にはお答えできない可能性があります。予めご了承ください。

太字イタリックアンダーラインハイパーリンク引用
[サインインしない場合はここにCAPTCHAを表示します]

コメント投稿後にScript Errorや500エラーが表示された場合は、すぐに再送信せず、ブラウザの「戻る」ボタンで一旦エントリーのページに戻り(プレビュー画面で投稿した場合は、投稿内容をマウスコピーしてからエントリーのページに戻り)、ブラウザをリロードして投稿コメントが反映されていることを確認してください。

コメント欄に(X)HTMLタグやMTタグを記述される場合、「<」は「&lt;」、「>」は「&gt;」と入力してください。例えば「<$MTBlogURL$>」は「&lt;$MTBlogURL$&gt;」となります(全て半角文字)