今回はjQueryのAjax関数を使った非同期通信処理をご紹介していきます。Ajaxを使うことでページ遷移をさせずにコンテンツを書き換えたり、他の処理を行いながらサーバとデータのやりとりを行うことができます。jQueryのajax関数はDeferredに対応しており、並列処理の記述が簡単にできたり、コードの汎用性が非常に高くなるメリットがあります。
Ajaxとは
Ajaxとはjavascriptを用いて非同期で通信を行い、その結果に応じて処理を行う技術を指します。
Webブラウザに実装されているJavaScriptのHTTP通信機能を使って、Webページのリロードを伴わずにサーバとXML形式のデータのやり取りを行って処理を進めていく対話型Webアプリケーションの実装形態。
Ajaxを使用することで画面遷移をせずにHTMLを更新することが可能なので、ユーザビリティの向上やサーバ負荷の軽減に繋がります。AngularJSなどで作成したシングルページアプリケーションはこの技術を中心に構成されています。
jQuery Ajaxサンプル
Ajaxのサンプルコードを記載します。jQueryのAjax関数に設定のためのJSONを渡して使用します。従来はAjaxのコールバックにsuccessやerror,completeなどを指定するのが一般的でしたが、jQuery1.8以降では非推奨となり、Deferredを使用したコールバックの記述をすることが推奨されています。
$(function() { $.ajax({ // リクエストメソッド(GET,POST,PUT,DELETEなど) type: 'POST', // リクエストURL url: 'request.php', // タイムアウト(ミリ秒) timeout: 10000, // キャッシュするかどうか cache: true, // サーバに送信するデータ(name: value) data: { 'param1': 'ほげ', 'foo': 'データ' }, // レスポンスを受け取る際のMIMEタイプ(html,json,jsonp,text,xml,script) // レスポンスが適切なContentTypeを返していれば自動判別します。 dataType: 'json', // Ajax通信前処理 beforeSend: function(jqXHR) { // falseを返すと処理を中断 return true; }, // コールバックにthisで参照させる要素(DOMなど) context: domobject }).done(function(response, textStatus, jqXHR) { // 成功時処理 //レスポンスデータはパースされた上でresponseに渡される }).fail(function(jqXHR, textStatus, errorThrown ) { // 失敗時処理 }).always(function(data_or_jqXHR, textStatus, jqXHR_or_errorThrown) { // doneまたはfail実行後の共通処理 }); });
他にも様々なオプションを持っていますが、今回はよく使うオプションのみを抜粋してご紹介しました。
jQueryにはAjax関数以外にも$.getJSONや$.get、$.postなど、リクエストメソッドやContentTypeによってAjax関数のエイリアスとなる関数が用意されています。
これらを使うことでコードをスマートに書くことができますが、通信先のメソッド、Content-Typeの変更やリクエスト時の設定の変更に対応ができなくなってしまいます。そのため個人的にはなるべく$.ajax関数で実装することをおすすめします。
jQueryのDeferredを使うメリット
Deferredを使うことでプログラム的にどんなメリットがあるのかを見ていきます。一番わかり易いところでいくと、Ajax処理を関数化した場合がイメージしやすいと思います。実際に見てみましょう。
※コールバック関数に使用する引数は説明のため省略しています。
Deferredを使用せずAjax処理を書いたコード
/** * Ajaxを使用してHTMLを取得し、更新する */ function updateHtml() { $.ajax({ type: 'GET', url: 'update.php', dataType: html, success: function(response) { $('#hoge').html(response); }, error: function() { alert('えらぁ'); }, complete: function() { alert('こんぷりーと'); } }); }
この関数はAjaxでHTMLを取得し、ある要素を更新するというものです。一見よくありそうなコードですが、成功時の処理、エラー時の処理、共通処理を変更することができません。コールバック関数を引数で渡すのも手ですが、コードの見通しが悪くなり、テストも難しくなります。
だからといって「responseが返ってくるかで処理分けちゃえばいいんじゃね!!」とか思って、下記のようなコードを書いてしまうとえらいことになります。
/** * AjaxでHTMLを取得する */ function getHtml() { var html = null; $.ajax({ type: 'GET', url: 'update.php', dataType: html, success: function(response) { html = response; }, error: function() { alert('えらぁ'); }, complete: function() { alert('こんぷりーと'); } }); return html; } // AjaxでHTMLを取得 var html = getHtml(); if(html) { // 更新 $('#hoge').html(html); } else { alert('えらぁ'); }
よくよく考えてみると当たり前なのですが、意外とハマる方もいるのではないでしょうか。この場合のgetHtml関数はAjaxの通信成功時もnullを返します。Ajax関数を実行している間は非同期で処理が走っているため、successコールバックのhtml = responseを待たずにreturn htmlをしてしまうのです。なので結局関数内でコールバックを書くか、コールバック関数をgetHtml関数に渡してやることになってしまいます。
Deferredを使用してAjax処理を書いたコード
上記のような問題が起こらないようにするには、Deferredの仕組みを使った処理を書きます。
/** * Ajaxを使用してHTMLを取得する */ function ajaxGetHtml() { var jqXHR = $.ajax({ type: 'GET', url: 'update.php', dataType: html }); return jqXHR; } var getHtml = ajaxGetHtml(); getHtml.done(function(response) { $('#hoge').html(response); }); getHtml.fail(function() { alert('えらぁ'); }); getHtml.always(function() { alert('コンプリート'); });
このようにAjax関数が返すjqXHRオブジェクトをそのまま返してやることでコードの見通しが良くなった気がします。この書き方にするメリットはこの3点です。
- コールバックの処理内容を呼び出し元で決定できる
- データ取得用関数として関数の機能をシンプルにできる
- Deferredを使用しているので非同期処理の管理がしやすい
非同期処理の管理については省略しますが、$.when関数を使用した非同期処理の管理を行うことができます。複雑な非同期処理を記述するときには必須のテクニックです。これについては別記事でご紹介したいと思います。
コメント
}).fali(function(jqXHR, textStatus, errorThrown ) {
faliってなんやねん
ご指摘ありがとうございます。修正いたします。
「jQueryのDeferredを使うメリット」の文章で、
よくよく考えてみると当たり前なのですが、意外とハマる方もいるのではないでしょうか。この場合のupdateHtml関数はAjaxの通信成功時もnullを返します。Ajax関数を実行している間は非同期で処理が走っているため、successコールバックのhtml = responseを待たずにreturn htmlをしてしまうのです。なので結局関数内でコールバックを書くか、コールバック関数をupdateHtml関数に渡してやることになってしまいます。
updateHtml関数は、getHtml関数の間違いでは?
ご指摘ありがとうございます。修正致しました。
一番最初に出てくるコードの
$.ajax(
の部分
{
が足りません。
ありがとうございます!修正いたしました。