Ajaxとは?
Ajaxとは、「Asynchronous JavaScript + XML」の略です。
「Asynchronous = 非同期」
という意味なので、Ajaxは非同期
なJavaScript
でXML
ということですね。
具体的にはこんな感じです。
[
{
"apple": "りんご",
"car": "くるま",
"pencil": "えんぴつ"
}
]
$.ajax({
url: 'english.json',
type: 'GET',
dataType: 'json'
}).done(function(data) {
console.log(data[0].apple); // りんご
});
XML
となっていますが、HTMLでもJSONでもPHPでも取得することができます。
english.json
には、簡単な英和辞典()のデータベースが入っています。
jQueryの$.ajax
でJSONを取得し、data
引数に渡しています。
$.ajaxで返ってくるもの。
data
引数の中身を見てみると、取得したJSONが格納されています。
.done(function(data){
console.log(data);
});
この状態だけを見ると、$.ajax()
は、URLプロパティで指定したファイルだけを取得しているように見えます。
が、実はdata
引数の中身は取得したデータの一部分で、実際にはもっと多くの情報を取得しています。
具体的には、$.ajax()
の場合、jqXHR
オブジェクトを取得しています。
$.ajax().done()
では、.done()
を第三引数まで指定することができます。
.done(function(data, textStatus, jqXHR) {
console.log('success');
console.log(data);
console.log(textStatus);
console.log(jqXHR);
});
先程のdata
引数は、第一引数にあたります。
これは、jqXHR
オブジェクトのresponseJson
プロパティ値と同じものです。
第二引数のtextStatus
は、通信の結果により、success
, notmodified
, nocontent
, error
, timeout
, abort
, parsererror
のどれかが返ります。
では、jqXHR
オブジェクトとは、なんでしょうか?
jqXHRオブジェクトとは?
jQueryの公式ドキュメントを見ると、こう書かれています。
The jqXHR Object
The jQuery XMLHttpRequest (jqXHR) object returned by $.ajax() as of jQuery 1.5 is a superset of the browser's native XMLHttpRequest object. For example, it contains responseText and responseXML properties, as well as a getResponseHeader() method. When the transport mechanism is something other than XMLHttpRequest (for example, a script tag for a JSONP request) the jqXHR object simulates native XHR functionality where possible.
Google先生の力をかりると、
jqXHRオブジェクト
jQuery 1.5以降の$ .ajax()によって返されるjQuery XMLHttpRequest(jqXHR)オブジェクトは、ブラウザのネイティブXMLHttpRequestオブジェクトのスーパーセットです。たとえば、responseTextおよびresponseXMLプロパティ、およびgetResponseHeader()メソッドが含まれています。トランスポート・メカニズムがXMLHttpRequest以外のもの(JSONP要求のスクリプト・タグなど)である場合、jqXHRオブジェクトは可能な場合はネイティブXHR機能をシミュレートします。
ネイティブXMLHttpRequestオブジェクトのスーパーセット
ここがポイントですね。
XMLHttpRequest
とは、ネイティブでJavaScriptが用意している、クライアントとサーバー間とをやり取りするためのAPIです。
参照:https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest
このAPIを叩くと、XMLHttpRequest
オブジェクトを取得することができます。
jqXHR
オブジェクトは、XMLHttpRequest
オブジェクトをjQueryがより使いやすい形に拡張したものです。
$.ajaxは、$.Deferredの様なPromiseを返す。
通信が成功したjqXHR
オブジェクトのpromise
プロパティの中身を見てみると、resolve
という値があります。
これは、$.Deferredと似たような仕組みで、ajax通信が終わると、Promiseを返します。
ajax通信が始まる前はpending
という値になっています。
ajax通信が成功すると値がresolve
に代わり、失敗するとrejected
に変わります。
resolve
になると、done()
が実行され、rejected
になるとfail()
が実行されます。
$.ajax({
url: 'english.json',
type: 'GET',
dataType: 'json'
}).done(function(data, textStatus, jqXHR) {
console.log(data[0].apple); // りんご
}).fail(function(jqXHR, textStatus, errorThrown){
console.log('通信失敗');
});
.fail()
は、引数が.done()
と異なります。
ちなみに、.then()
を使うと、成否の両方を繋げて記述することができます。
また、.always()
は、成否によって引数の値が変化します。
$.ajax({
url: 'english.json',
type: 'GET',
dataType: 'json'
}).then(function(data, textStatus, jqXHR) {
console.log('成功');
}, function(jqXHR, textStatus, errorThrown) {
console.log('失敗');
}).always(data|jqXHR, textStatus, jqXHR|errorThrown) {
// 成功すると.done()の引数になり、失敗すると.fail()の引数になる。
});
より詳しく知りたい方は、公式ドキュメントをご確認くださいm(_ _)m
http://api.jquery.com/jquery.ajax/
applyメソッドを$.whenで使用し、順番を保証。
さて、ここからは少し実践的、かつ、ピンポイントなお話をします。
Ajax通信は非同期な処理なので、次の様な処理で、順番を保証したいときは、少し工夫が必要になります。
第一話:プロローグ
第二話:君と夏の終わり将来の夢〜(このあと3万行ぐらいリピート)
第三話:エピローグ
let index = []; // ['第一話:プロローグ', '第二話:君と夏の終わり〜', '第三話:エピローグ']の順番で格納したい。
const textFiles = [
'01.txt',
'02.txt',
'03.txt'
];
for (let i = 0; i < textFiles.length; i++) {
$.ajax({
url: textFiles[i],
type: 'GET',
dataType: 'json'
}).done(function(data) {
index.push(data);
});
}
console.log(index); // ['第一話:プロローグ', '第二話:君と夏の終わり〜', '第三話:エピローグ']とは限らない。
このような書き方ですと、Promiseが返ったタイミングで.done()
が実行されてしまうので、取得に時間がかかると順番が変わってしまいます。
そこで、$.when.apply()
を使い、順番を保証してあげます。
let jqXHRs = [];
let index = [];
const textFiles = [
'01.txt',
'02.txt',
'03.txt'
];
for (let i = 0; i < textFiles.length; i++) {
jqXHRs.push($.ajax({
url: textFiles[i],
type: 'GET',
dataType: 'text'
}));
}
$.when.apply($, jqXHRs).done(function(){
for (let i = 0; i < arguments.length; i++) {
index.push(arguments[i][0]);
}
console.log(index); // ['第一話:プロローグ', '第二話:君と夏の終わり〜', '第三話:エピローグ']
});
$.ajax()
で取得したjqXHR
オブジェクトは、.push()
された順番にjqXHRs
配列に格納されます。
ポイントは、.apply()
を利用し、$.when()
に可変長引数を渡しているところです。
.apply()
の第一引数は、$.when()
関数を呼び出す際に渡すthis
の値です。
今回は、jqXHR
オブジェクトの親オブジェクトを呼び出しているので、$
を指定しています。
そして、第二引数でjqXHRs
配列を指定することにより、すべてのjqXHR
オブジェクトがPromiseを返したタイミングで、$.when()
は.done()
を実行しています。
実引数のarguments
は、.done()
の仮引数であるdata
, textStatus
, jqXHR
の3つの引数を、配列のような形で所有しているので、for文で回してあげることにより、順番を保証したままdata
を取得することができます。
もし、意味がわからなかったら。。。
ここまでの話の意味がわからなかった方は、オライリーの「開眼!JavaScript」を一読することをおすすめします。
とても勉強になります。
ECMAScript2015でXMLHttpRequest
おまけで、ECMAScript2015
でXMLHttpRequest
オブジェクトを取得する方法を書いておきます。
const _url = 'english.json'; // クロスドメインに注意
const foo = (url) => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = () => resolve(xhr.response);
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
});
};
foo(_url).then((data) => {
const myData = JSON.parse(data); // IE11ではjsonがパースされないため、文字列として受け取りパースする。
console.log(myData);
}).catch((error) => {
console.log(error);
});
ご参考までに。