Deferredその1:何故をDeferred使うかの理由
2016/05/07
Deferredその1:何故をDeferred使うかの理由
さて、jQuery.Deferred(以下、Deferred)の使い方についての記事を書こうかと思います。
Deferredを使う主なメリット
・コールバックの入れ子(ネスト)によるスパゲティコードを防げる。
・可読性の高い並列処理のコードを書ける。
・これにより非同期処理の記述や処理をスムーズに進められる。
とまあ、このようなメリットがあります。
まずは、このDeferredを敢えて使わないパターンをいくつか挙げて、その後にDeferredを使った簡単な処理を記述しようかと思います。
なお、Deferredの様々な詳細な書き方とかについては、他の記事に書いていきます。
ここではDeferredを使用しないパタートの比較という事で。
Deferredを使わないパターン
リクエストのパラメーターに文字列を囲んで返すテスト用のPHP
1.このパラメータは"contents"があり、"パラメーターのキーをcontentsとして受け取った値は"と"です。"で囲んだものを出力。
test-deferred-reason.php
// ※これはhtmlではなくphpファイルです、<?phpと?>で囲んでください $contents = $_SERVER["REQUEST_METHOD"] == "GET" ? $_GET["contents"] : $_POST["contents"] ; echo "パラメーターのキーをcontentsとして受け取った値は" . $contents . "です。";
特に何もしないで書いたajax通信のjQueryサンプル
1.ajax通信にてテストphpにリクエストをパラメータ付きで送信
2.divタグのresultクラスにレスポンスで返って来た文字列をtextメソッドでセット
3.この文字列をセットするタイミングは$.ajaxメソッドの外、Deferredに関しては何もしない
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <script src="../../js/jquery-1.12.2.min.js"></script> <script> $(function(){ var resAjax = ""; $.ajax({ url: "test-deferred-reason.php", data: "contents=ajax-test", success: function(data) { resAjax = data; } }); $("div.result").text("ajax通信で受け取った結果:" + resAjax); }); </script> </head> <body> <div class = "result"></div> </body> </html>
特に何もしないで書いたajax通信のjQueryサンプルコードの結果
ぱっと見はresAjax変数にajax通信(リクエストメソッドは指定していないのでデフォルトのget送信)からのレスポンスの返る値が入るように思われますが、divタグ(class = "result")には表示されません。
正確には文字列はtextメソッドによりセットはされるのですが、その一連の処理より先にブラウザの表示がされてしまう為、結果が見れないという事になります。
sleep関数を使って処理を遅らせてブラウザで表示される前に$.ajax()でresAjax変数に値がセットされるのを待つという手もありますが、非現実的です。
では、ここでDeferredを使わない他の2つの方法を試してみます。
Deferredを使わないでdivタグに結果を表示する方法その1(asyncオプションを同期通信にする)
1.ajax通信にてasyncオプションをfalseして同期通信
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <script src="../../js/jquery-1.12.2.min.js"></script> <script> $(function(){ var resAjax = ""; $.ajax({ url: "test-deferred-reason.php", data: "contents=ajax-test", // この様にasyncオプションをfalseとすれば同期通信となる。 // ただし、その間はブラウザがロックされてクリックなどのアクションを受付なくなるので、非推奨とされている。 async: false, success: function(data) { resAjax = data; } }); $("div.result").text("ajax通信で受け取った結果:" + resAjax); }); </script> </head> <body> <div class = "result"></div> </body> </html>
Deferredを使わないでdivタグに結果を表示する方法その1のサンプルコードの結果
この様にasyncオプションをfalseとすれば同期通信となりブラウザに表示される前にdivタグにテキストがセットされます。
ただし、その間はブラウザがロックされてクリックなどのアクションを受付なくなるので、非推奨とされています。
次にコールバック関数を使っての対応を試してみましょう。
Deferredを使わないでdivタグに結果を表示する方法その2(コールバックを使う)
1.ajaxCallbackという変数にajax通信のコールバックオブジェクトを作成
2.ajax通信の成功時にtest-deferred-reason.phpから返ってきたレスポンスを引数に代入。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <script src="../../js/jquery-1.12.2.min.js"></script> <script> $(function(){ var resAjax = ""; var ajaxCallback = function(callback){ $.ajax({ url: "test-deferred-reason.php", data: "contents=ajax-test", success: function(data) { callback(data); } }); } ajaxCallback(function(data){ resAjax = data; $("div.result").text("ajax通信で受け取った結果:" + resAjax); }); }); </script> </head> <body> <div class = "result"></div> </body> </html>
Deferredを使わないでdivタグに結果を表示する方法その2、コールバックのサンプルコードの結果
このようにコールバックを使って対応も可ですが、処理によっては、そのコールバック関数自体が複数の入れ子になり、コードの可読性というものが低くなる場合が多いです。
そこで便利なので、deferredの出番というわけです。
Deferredを使うパターン
お待たせいたしました!
いよいよDeferredを使うパターンを見ていきましょう。
Deferredを使ってみる(Deferredの状態をresolveとして.done()をコールバック)
1.getAjaxPromise()の中でDeferredオブジェクト作成
2.ajax通信が成功しsuccess:に入ったならDeferredの状態をresolveにする
3.DeferredのPromiseを返す
4.getAjaxPromise()より返されたPromiseの.done()を実行
5.resolveの時に渡された引数の文字列を"ajax通信で受け取った結果:" に追加してdivタグ(class = "result")のテキストにセットする。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <script src="../../js/jquery-1.12.2.min.js"></script> <script> $(function(){ var resAjax = ""; // DeferredのPromiseオブジェクト var ajaxPromise = getAjaxPromise(); function getAjaxPromise(){ // Deferredオブジェクト作成 var defer = new $.Deferred; $.ajax({ url: "test-deferred-reason.php", data: "contents=ajax-test", success: function(data) { // Deferredの状態をresolveとする。 // これによりコールバック関数は.done()となる。 defer.resolve(data); } }); return defer.promise(); } // DeferredのPromiseオブジェクト // 状態がresolveの場合は.doneが呼ばれる ajaxPromise.done(function(data) { resAjax = data; $("div.result").text("ajax通信で受け取った結果:" + resAjax); }); }); </script> </head> <body> <div class = "result"></div> </body> </html>
Deferredを使ってみるのサンプルコードの結果
Deferredを使うには、このように処理からDeferredオブジェクトを作成し、処理の中で状態を指定して引数を渡します。
その後で 状態がresolveやrejected等により.done()や.fail()等に処理を分けてコードを書いていきます。
これが簡単なDeferredのサンプルの例となります。
※Deferredの様々な詳細な書き方とかについては、他の記事に書いていきます。