TopJavaScriptjQuery > 2012年10月
2012年10月11日

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

October 11,2012 12:03 AM
Tag:[, ]
Permalink

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

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

Comments [0] | Trackbacks [0]
2012年10月 2日

jQuery.ajax()のまとめ

October 2,2012 12:55 AM
Tag:[, ]
Permalink

jQuery.ajax()について逆引きリファレンスっぽくまとめてみました。

まとめた理由は、ネットで「jQuery.ajax」や「jQuery.ajax サンプル」などで調べても、いい感じの内容がなかなかヒットしないことと、よくヒットするサイトの情報が古かったりする(1.4で止まっているとか)ためです。

ということで、2012年10月現在の「jQuery.ajax()」などをざっと調べて作ってみました。

初心者向けの内容です。すべてのオプションは網羅できていません。とりあえずサンプルコードがほしい方は15項をご覧ください。

若番から必要と思われるものを順番に並べているつもりですが、後半は適当です。また、各項のサンプルはなんとなく積み上げていく感じにしています。

調べている間にも3つくらい新しい発見(といっても古い情報ですが…)があり、jQueryが日々進化していることを感じました。

勉強がてらの記事なので間違いがありましたらどこかでつぶやいてください。

1.基本

全体に共通する基本的な事項です。

まず、「:」の右辺に記述する文字が文字列の場合、クォーテーションまたはダブルクォーテーションで括ってください。数値・変数・真偽値は括らなくても大丈夫です。左辺は括る必要はありません。

$.ajax({
    url: 'hoge.html', // 文字列
    ...
var url = 'hoge.html';
$.ajax({
    url: url, // 変数
    ...
$.ajax({
    timeout: 10000, // 数値
    ...
$.ajax({
    async: true, // 真偽値
    ...

また、後述する各オプションの末尾にカンマを付け忘れないよう、気をつけましょう(一番最後のオプションの末尾のカンマは不要)。

2.HTTPのリクエストメソッドを指定するには?

HTTPのリクエストメソッド(POST/GET)を指定するには「type」オプションを指定します。デフォルトは「GET」です。

POSTの場合

$.ajax({
    type: 'POST',
    ...

GETの場合

$.ajax({
    type: 'GET',
    ...

3.送信先URLを指定するには?

送信先URLは「url」オプションに設定します。

$.ajax({
    type: 'POST',
    url: 'http://user-domain/hoge.php',
    ...

4.クエリーパラメータを指定するには?

「data」オプションに設定します。

$.ajax({
    type: 'GET',
    url: 'http://user-domain/hoge.php',
    data: {
        id: 1,
        mode: 'hoge',
        type: 'entry'
    },
    ...

GETメソッドであれば次のようなリクエストになると思います。

http://user-domain/hoge.php?id=1&mode=hoge&type=entry

5.受信データタイプの指定は?

受信データタイプは「dataType」オプションに設定します。デフォルトは自動推測ですが、レスポンスを期待通り受信あるいは処理できない場合は設定してみましょう。

プレーンテキストを受信する場合

$.ajax({
    type: 'POST',
    url: 'http://user-domain/hoge.txt',
    dataType: 'text',
    ...

HTMLデータを受信する場合

$.ajax({
    type: 'POST',
    url: 'http://user-domain/hoge.html',
    dataType: 'html',
    ...

XMLデータを受信する場合

$.ajax({
    type: 'POST',
    url: 'http://user-domain/hoge.xml',
    dataType: 'xml',
    ...

JavaScriptデータを受信する場合

$.ajax({
    type: 'POST',
    url: 'http://user-domain/hoge.js',
    dataType: 'script',
    ...

JSONデータを受信する場合

$.ajax({
    type: 'POST',
    url: 'http://user-domain/hoge.json',
    dataType: 'json',
    ...

JSONの場合、jQuery.getJSON()を使ってもOKです。

JSONPを受信する場合

$.ajax({
    type: 'POST',
    url: 'http://user-domain/hoge.php',
    dataType: 'jsonp',
    ...

JSONPの場合、URLに「callback=?」という特殊なクエリーが自動的に付与されます。「?」の部分は任意の文字列を設定してサーバにコールバック関数名として送信します。

サーバ側ではこの「callback=?」の部分を読み取り、jsonpのコールバック関数名として返却値に設定する必要があります。通信が成功すれば「success」オプションで受信できます。

コールバック関数のキー名を指定したい場合は、「jsonp」オプションにコールバック関数のキーを設定します。

$.ajax({
    type: 'POST',
    url: 'http://user-domain/hoge.php',
    dataType: 'jsonp',
    jsonp: 'jsoncallback',
    ...
});

コールバック関数名は「jsonpCallback」オプションで設定可能です。

$.ajax({
    type: 'POST',
    url: 'http://user-domain/hoge.php',
    dataType: 'jsonp',
    jsonp: 'jsoncallback',
    jsonpCallback: 'foo',
    ...
});

クロスドメインの場合は、さらに「crossDomain」オプションを付与します。「true」を設定すればクロスドメイン通信が可能です。

$.ajax({
    type: 'POST',
    url: 'http://user-domain/hoge.php',
    dataType: 'jsonp',
    jsonp: 'jsoncallback',
    jsonpCallback: 'foo',
    crossDomain: true,
    ...
});

1.5以降では複数のデータ型を指定できるようです。

    dataType: 'text xml',

6.キャッシュされたデータを受信したくないのですが?

「cache」オプションを設定します。デフォルトは「true」で、「false」を設定すればキャッシュされなくなるようです。

$.ajax({
    type: 'POST',
    url: 'http://user-domain/hoge.php',
    data: {
        id: 1,
        mode: 'hoge',
        type: 'entry'
    },
    dataType: 'html',
    cache: false,
    ...

7.結果の受信は?

「success」「complete」「error」オプションで受信します。1.8では「done」「fail」「always」で受信できます。

「success」「done」オプションは通信が成功したとき、「complete」「always」オプションは通信が完了したとき、「error」「fail」オプションは通信に失敗したときに起動されます。

$.ajax({
    type: 'POST',
    url: 'http://user-domain/hoge.php',
    data: {
        id: 1,
        mode: 'hoge',
        type: 'entry'
    },
    dataType: 'html',
    success: function( data, textStatus, jqXHR ) {
        // ...
    },
    error: function( jqXHR, textStatus, errorThrown ) {
        // ...
    },
    complete: function( jqXHR, textStatus ) {
        // ...
    }

1.8では、

$.ajax({
    url: 'http://user-domain/hoge.php',
    type: 'POST',
    data: {
        id: 1,
        mode: 'hoge',
        type: 'entry'
    },
    dataType: 'html'
})
.done(function( data ) {
        // ...
})
.fail(function( data ) {
        // ...
})
.always(function( data ) {
        // ...
});

「success」オプションで起動される関数の引数は3つですが、最初のdataのみでも大丈夫かと思います。textStatusはリクエストの状態(「success」など)を返却します。

    success: function( data ) {
        $('#foo").html( data );
    },

パラメータdataには、「dataType:」で指定したデータが設定されています。設定したdataTypeと受信したデータ型が一致していないと、正常に処理できない可能性があります。

errorの引数は3つで、順にjqXHRオブジェクト、エラー内容、補足的な例外オブジェクトを受け取ります。第2引数には "timeout", "error", "notmodified", "parsererror"などが返ります。

「done」「fail」「always」のパラメータも「success」「complete」「error」と同じと思われますが確認できていません。すいません。

話がちょっとそれますが、「jqXHR」は1.5から返却されるようになったオブジェクトで、1.4.xまでの「XMLHttpRequest」と違い、Promiseインターフェースというものを備えていて、これによりdoneやfailによるコールバック登録が行えるようになっています。

8.「success」と「complete」の違いは?

「success」は通信に成功した場合のみ起動されます。「complete」は「error」を含め、処理が完了した場合に必ず起動されます。

Javaが分かる人は「try/catch/finally」と対応させれば理解が容易になると思います。

9.送信前に処理を行いたいが?

「beforeSend」オプションを設定します。

$.ajax({
    url: 'http://user-domain/hoge.php',
    type: 'POST',
    beforeSend: function ( jqXHR, settings ) {
        // ...
    },
    success: function (data) {
        // ...
    },
    ...

第2パラメータの「settings」は、jQuery.ajax()の設定オプションを参照できます。

    beforeSend: function ( jqXHR, settings ) {
        alert( setting.type ); // 'POST'
        alert( setting.url );  // 'http://user-domain/hoge.php'
    },

10.同期で通信したいが?

「async」オプションを設定します。「false」を設定すれば、jQuery.ajax()の後方の処理が待ち合わせされます。

下の例では「success」または「error」の処理が終わってからalertが実行されます。非同期の場合は(多分)alertが先に実行されます。

$.ajax({
    async: false,
    url: 'http://user-domain/hoge.php',
    type: 'POST',
    success: function( data ) {
        // ...
    },
    error: function( data ) {
        // ...
    },
});
alert("OK");

なお「false」を設定しても「beforeSend」が一番早く実行されます。

注:jQuery 1.8では「async: false」の記述は非推奨となっており、「you must use the complete/success/error callbacks」と書かれています。

11.ステータスコードで処理を振り分けたいが?

「statusCode」オプションを利用します。

$.ajax({
    async: false,
    url: 'http://user-domain/hoge.php',
    type: 'POST',
    statusCode: {
        200: function(){
            console.log("200");
        }, 
        404: function(){
            console.log("404");
        }
    }
});

レスポンスデータも受け取れます。

    statusCode: {
        200: function( data ){
            console.log( data );
        }, 

12.最後のリクエスト以降で変更があったことを判定したいが?

「ifModified」オプションを利用します。「true」を設定すれば、Last-Modifiedヘッダをチェックします。

$.ajax({
    async: false,
    url: 'http://user-domain/hoge.php',
    type: 'POST',
    ifModified: true,
    ...

13.HTTP認証が必要だが?

「username」オプションと「password」オプションを設定します。

$.ajax({
    async: false,
    url: 'http://user-domain/hoge.php',
    type: 'POST',
    username: 'foo',
    password: 'bar',
    ...

14.タイムアウトさせたいが?

「timeout」オプションを設定します。単位はmsです。

$.ajax({
    async: false,
    url: 'http://user-domain/hoge.php',
    type: 'POST',
    timeout: 10000,
    ...

15.すぐに使えるサンプルは?

POSTデータで「http://user-domain/hoge.php」を起動するサンプルをいくつか作ってみました。返却値はHTMLで受け取ります。

$.ajax({
    url: 'http://user-domain/hoge.php',
    type: 'POST',
    data: {
        id: 1,
        mode: 'hoge',
        type: 'entry'
    },
    dataType: 'html',
    success: function( data ) {
        // ...
    },
    error: function( data ) {
        // ...
    },
    complete: function( data ) {
        // ...
    }
});

1.5以降であれば、jQuery.ajax()の返却値であるjqXHRオブジェクトを使って、次のように記述できます。

$.ajax({
    url: 'http://user-domain/hoge.php',
    type: 'POST',
    data: {
        id: 1,
        mode: 'hoge',
        type: 'entry'
    },
    dataType: 'html'
})
.success(function( data ) {
        // ...
})
.error(function( data ) {
        // ...
})
.complete(function( data ) {
        // ...
});

それぞれのコールバックを分割することもできます。変数jqxhrのスコープに気をつけてください。

var jqxhr = $.ajax({
    url: 'http://user-domain/hoge.php',
    type: 'POST',
    data: {
        id: 1,
        mode: 'hoge',
        type: 'entry'
    },
    dataType: 'html'
});
jqxhr.success(function( data ) {
        // ...
});
jqxhr.error(function( data ) {
        // ...
});
jqxhr.complete(function( data ) {
        // ...
});

1.8では「jqXHR.success」「jqXHR.error」「jqXHR.complete」が廃止される予定です(上の2つのサンプル)。次のように「jqXHR.done」「jqXHR.fail」「jqXHR.always」に書き換える必要があります。

$.ajax({
    url: 'http://user-domain/hoge.php',
    type: 'POST',
    data: {
        id: 1,
        mode: 'hoge',
        type: 'entry'
    },
    dataType: 'html'
})
.done(function( data ) {
        // ...
})
.fail(function( data ) {
        // ...
})
.always(function( data ) {
        // ...
});

16.参考サイト

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

Comments [0] | Trackbacks [0]
Now loading...
ギターに入った猫
掲載広告募集
Styles
Font Size
Default
For defective color vision
Gray Scale
RGB Color
Search this site

このブログをメールで購読する by:FeedBurner

AMN
Categories
Monthly Archives
2020年
2019年
2018年
2017年
2016年
2015年
2014年
2013年
2012年
2011年
2010年
2009年
2008年
2007年
2006年
2005年
2004年
2003年
BlogPeople
Syndicate this site
FeedBurner(RSS1.0/RSS2.0/Atom)
Counter
これまでのアクセス
Powered by
Movable Type 6.0.3