TAKAYA OHTAやOPERAのようにシームレスな画面遷移を実現する場合にAjaxが使われます。
SPA(Single Page Application)などデスクトップアプリのように操作できるのですが、それにもAjaxなどの非同期通信が使われています。具体的なサービスを挙げるとFacebookやTwitterですね。
今回、Ajaxや非同期通信についてあんまり理解せずに使っていたのでまとめてみました。
非同期通信とは?
まず、ウェブページなどを閲覧するためにHTTP通信をしてますよね。
ざっくり説明すると、まずWebブラウザ(クライアント)がウェブサイト(サーバー)にHTTPリクエストを送ります。
サーバーが処理を行い、その結果をブラウザに返すのがHTTPレスポンスです。
ブラウザがそれを表示することで、ユーザーがウェブページを見ることができます。
この流れがHTTP通信です。
同期通信はリクエストを出してからレスポンスを受け取るまで、他の処理を行うことができません。
それに対して非同期通信は、リクエストを投げてもブラウザの操作が行うことができます。そしてサーバーからレスポンスを受け取ると、受信処理を実行します。
ページの一部だけ変更するのに同期通信をしていたら、その間操作できないのでユーザビリティが損なわれますよね。
そんなときに非同期通信を使えば、ユーザビリティを損なうことなくページを更新することができます。
メリット・デメリット
次に非同期通信を使うメリット・デメリットをそれぞれ表にまとめてみました。
メリット | 説明 |
---|---|
操作性の向上 | サーバーが処理を行っている間に操作できる点 |
パフォーマンスの向上 | ページの一部のみ更新するため、通信量の削減 |
機能を実現しやすくなる | 編集中の文章を一時保存するなどの機能を ユーザーに意識させることなく実装することができる |
デメリット | 説明 |
---|---|
クロスブラウザ処理の必要 | JavaScriptで異なるドメインのサービスに接続すると エラーが起こるため 回避するための方法が必要 |
逆にサーバーの負荷が増える場合がある | 不用意に非同期通信ばかり行っていたら、 サーバーの負荷が増える |
コードがいつ処理されているのか分かりづらくなる | コードの量が増えていくと いつ非同期処理が実行されているか、分かりづらくなる |
Ajaxの概要
Ajax(エイジャックス)とは、簡単に言ったらJavaScriptで非同期通信を行うことです。
Ajaxを使っているものを挙げるとGoogle マップが有名です。
地図をスライドするとその先の地図が表示されますよね。スライドしている間に足りない地図のデータをAjaxでリクエストしているから、ぬるぬる地図を動かすことができるのです。
もしAjaxがなければスライドする度にページを再読み込みする必要があるので、Ajaxに感謝です。
AjaxはHTML、XHTML、CSS、JavaScript、DOM、XML、XSLT、XMLHttpRequestオブジェクトなど既存の技術を組み合わせたものです。アプローチを指した言葉であり、Ajax自体がある種の技術という訳ではありません。
Ajaxは正式名称はAsynchronous Javascript And XMLです。XMLとありますがJSON、 HTML、テキストファイルなど、様々な形式の情報で送受信できます。最近ではXMLよりJSONの方がよく使われています。
方法
Ajaxを行う方法はいくつかあるのですが、今回はXMLHttpRequest APIを使う方法を紹介します。
最初にJavaScriptで書いた場合、次にjQueryで書いた場合を説明していきます。
JavaScriptで書いた場合
[common.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var xhr = new XMLHttpRequest(); xhr.open("GET", "/bar/foo.txt"); xhr.onreadystatechange = function (e) { if (xhr.readyState === 4) { if (xhr.status === 200) { // 処理 } else { // } } }; xhr.send(); |
解説していきます。まずJavaScriptがサーバーにHTTPリクエストを送るために、XMLHttpRequestオブジェクトのインスタンスを作成します。
[common.js]
1 2 3 | var xhr = new XMLHttpRequest(); |
openメソッドでリクエストの初期化を行います。
引数は
・method: HTTPリクエストメソッド。 “GET”, “POST”, “PUT”, “DELETE”, など。
・url: リクエストの送り先のURL。
・async: 論理値。falseだと同期通信になる。既定値は true。
・user,password: ベーシックHTTP認証のユーザーとパスワード。既定値は null。
を取ります。
[common.js]
1 2 3 | xhr.open("GET", "/bar/foo.txt"); |
今回common.jsのパス/bar/foo.txtに対して、GET通信をしようとしています。
次にサーバーにリクエストを送ります。コードの順番と違うのですが、この部分ですね。
[common.js]
1 2 3 | xhr.send(); |
非同期の場合、リクエストが送信されるとメソッドはすぐ戻ります。結果は次のイベントによって配信されます。
同期の場合はメソッドはレスポンスを受け取るまで戻りません。
引数でリクエストの本文データを送ることができます。ただしリクエストメソッドがリクエストの本文を受け取れるものに限ります。リクエストメソッドが本文を受け取れない場合、引数は無視されてnullに設定されます。
最後にレスポンスに対するイベントハンドラを設定し、受動処理を指定します。
readyStateプロパティが変化するたびに、こちらの処理が走ります。
readyStateプロパティはXMLHttpRequestクライアントの状態を返します。要は非同期通信の状態を返しています。
XMLHttpRequestクライアントの状態について表にまとめてみました。
値 | 説明 |
---|---|
0 | XMLHttpRequestオブジェクトのインスタンスは作成済み。 openメソッドは呼び出していない |
1 | openメソッドが呼び出し済み(ロード中) |
2 | sendメソッドが呼び出し済み。 ヘッダーとステータスが利用可能 |
3 | ダウンロード中。 レスポンスボディを受け取っている |
4 | 取得操作完了。 データ転送が成功したか、失敗したかのどちらか |
またstatusプロパティでHTTPステータスコードを取得しています。HTTPステータスコードとはサーバーのレスポンスの意味を表す3桁の数字コードです。これで非同期通信の処理の結果を取得してるのですね。
HTTPステータスコードの主な値を表にまとめてみました。
値 | 説明 |
---|---|
200 | OK。リクエストが成功。 HTTPメソッドにより成功の定義が異なる |
401 | Unauthorized。認証が必要 |
403 | Forbidden。アクセス拒否。 401と違ってサーバーにクライアントの識別子が知られている |
404 | Not Found。リクエストされたソースが発見できない。 通信先が有効であるが、リソースが存在しない |
500 | Internal Server Error。サーバー側で処理方法がわからない事態が発生 |
503 | Service Unavailable。サーバーがリクエストを処理する準備ができていない。 主な原因としてサーバーがメンテナンスや過負荷で落ちていることが挙げられる |
今回は、HTTPステータスコードが200の値を返す(処理が成功)ときにサーバーから受け取ったテキストをコンソールに出力します。それ以外の値なら、レスポンスメッセージをコンソールに出力します。
[common.js]
1 2 3 4 5 6 7 8 9 10 11 | xhr.onload = function (e) { if (xhr.readyState === 4) { if (xhr.status === 200) { console.log(xhr.responseText); } else { console.error(xhr.statusText); } } }; |
jQueryで書いた場合
BRISKでは主にjQueryでAjaxを扱うことが多いです。jQueryでの基本の書き方を説明したいと思います。
[common.js]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | $.ajax({ type: 'POST', // HTTPリクエストメソッドの指定 url: '/bar/foo.txt', // 送信先URLの指定 async: true, // 非同期通信フラグの指定 dataType: 'json', // 受信するデータタイプの指定 timeout: 10000, // タイムアウト時間の指定 data: { id: 1, name: 'brisk' // クエリパラメータの指定。サーバーに送信したいデータを指定 } }) .done(function(data) { // 通信が成功したときの処理 }) .fail(function() { // 通信が失敗したときの処理 }); .always(function() { // 通信が完了したときの処理 }); |
オプションの説明を下の表でまとめました。
オプション名 | 説明 |
---|---|
type | HTTPリクエストメソッドを指定 GETかPOSTなど。初期値: GET |
url | リクエストを送信する先のURL 省略した場合、呼び出し元に送信 |
async | 非同期通信フラグ 初期値: true(非同期通信) falseだと同期通信になる |
dataType | サーバーからレスポンスされるデータの型を指定 返ってくるデータのMIMEタイプとの整合性をとる 値の例: xml、html、script、json、jsonp、text |
timeout | タイムアウト時間をミリ秒で指定 |
data | サーバーに送信する値 オブジェクトが指定された場合、 クエリー文字列に変換されてGETリクエストとして付加される |
$.ajax()はjqXHRオブジェクトを返します。jqXHRオブジェクトとはXMLHttpRequestオブジェクトのスーパーセットです。XMLHttpRequestオブジェクトを使いやすいように拡張したものみたいですね。
jqXHRオブジェクトはPromiseインターフェースを実装していています。なので受信したデータをコールバック関数で受け取ることなく、done()やfail()で取得できるのですね!
then()でもデータを取得できます。done()とfail()をまとめてかけるのがthen()です。
[common.js]
1 2 3 4 5 6 7 8 9 10 11 | $.ajax({ // オプション指定 }) .then(function(data) { // 通信が成功したときの処理 }, function() { // 通信が失敗したときの処理 }); |
done()、fail()、always()の代わりにsccess()、error()、complete()で書いている場合がありますが、jQuery 1.8で非推奨になりました。
まとめ
サラッと書いてあるコードがこんな動きをしてたんですね。
調べながら書いていたのですが、ドンドン知らない単語が出てきて大変でした。Ajaxを理解するにはJavaScriptだけではなくHTTP通信の知識も必要で、Webの基礎知識が大切だと思いました。
リッチなサイトでは非同期処理はもはや欠かせないので、理解して使っていきたいですね。
これを読んで、少しでも非同期通信について理解が深まったら幸いです。
参考文献
MDN
現代の JavaScript チュートリアル ネットワークリクエスト XMLHttpRequest
jQuery.ajax()のまとめ
JavaScript 日本語リファレンス
jQuery 日本語リファレンス
山田祥寛,[改訂新版]JavaScript本格入門,技術評論社,2016