読者です 読者をやめる 読者になる 読者になる

感謝のプログラミング 10000時間

たどり着いた結果(さき)は、感謝でした。

jQuery Deferredを使って、2つのリクエストの結果を待ち合わせて後続の処理を実行する。

<スポンサーリンク>

基礎知識

jQuery Deferredは、jQueryのバージョン1.5からサポートされた機能で、Ajaxのような非同期処理を監視することができる。

下記の2つのリンクが非常に詳しい。
http://s3pw.com/qrefy/deferred.done/
爆速でわかるjQuery.Deferred超入門

defferedとは、「遅延された」オブジェクトという意味で、処理状態に応じて実行する関数を管理することができる。

jQuery DefferedのAPIドキュメントは以下。
http://api.jquery.com/category/deferred-object/

Promise .when()で処理を待ち合わせる

以下を参考にサンプルを作ってみる。
http://api.jquery.com/jquery.when/
サーバ側は簡単なPlay Frameworkを使って作成。
サーバはこんなことをしている。
・「/deffered1」宛にリクエストがきたら、5秒待ってメッセージを返す
・「/deffered2」宛にリクエストがきたら、2秒待ってメッセージを返す。

で、クライアントは「/deffered1」、「/deffered2」の両方のリクエストの結果が返ってきて初めて結果表示の処理を実行する、ということをやりたい。
まずはサーバ側のJava

public static Result deffered1() {
	String message = "hello! deffered! I'm ONE";
	ObjectNode result = Json.newObject();
	result.put("message", message);
	try {
		//5秒待つ
		Thread.sleep(5000);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	return ok(result);
}

public static Result deffered2() {
	String message = "hello! deffered! I'm TWO";
	ObjectNode result = Json.newObject();
	result.put("message", message);
	try {
		//2秒待つ
		Thread.sleep(2000);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	return ok(result);
}

で、以下のJavaScriptが待ち合わせを実現する。

$(function() {
	var $startBtn = $("#startBtn").on('click', function() {
		$startBtn.prop('disabled', true);
		var promise1 = $.post("/deffered1");
		var promise2 = $.post("/deffered2");

		$.when(promise1, promise2).done(function (res1, res2) {
			console.log(res1);
			$("#result").append(res1[0].message + "<br/>");
			$("#result").append(res2[0].message + "<br/>");
			$startBtn.prop('disabled', false);
		});
	});
});

このJavaScriptを以下のindex.scala.htmlで読み込んでブラウザを見てみよう。

@(msg: String)

@import helper._
@import helper.twitterBootstrap._
@main("Sample Page") {
	<script src="@routes.Assets.at("javascripts/defferedSample.js")"
		type="text/javascript"></script>
	<h1>リクエストの待ち合わせサンプル</h1>
	<button id="startBtn">リクエスト</button><br/>
	<hr/>
	<div id="result"></div>
}

すると、5秒後くらいにこんなメッセージが「同時に」表示される。
f:id:sho322:20140108031400j:plain

jQuery Deferredで待ち合わせ

同じことをjQuery Deferredを使ってやってみるとこんな感じ。

$(function() {
	var $startBtn = $("#startBtn").on('click', function() {
		$startBtn.prop('disabled', true);
		var message1 = null;
		var message2 = null;

		$.when(firstRequest(), secondRequest()).done(result);

		function firstRequest() {
			return $.Deferred(function() {
				var self = this;
				$.ajax({
					type: "POST",
					url: "/deffered1",
					success: function(res) {
						message1 = res.message;
						console.log(message1);
						self.resolve();
					}
				});
			});
		}

		function secondRequest() {
			return $.Deferred(function() {
				var self = this;
				$.ajax({
					type: "POST",
					url: "/deffered2",
					success: function(res) {
						message2 = res.message;
						console.log(message2);
						self.resolve();
					}
				});
			});
		}

		function result() {
			$("#result").append(message1 + "<br/>");
			$("#result").append(message2 + "<br/>");
			$startBtn.prop('disabled', false);
		}

	});
});

f:id:sho322:20140108031422j:plain

画像のコンソール部分に出ているように、先にTWOの結果が返ってきて、
次にONEの結果が返ってくる。

にも関わらず、TWOが早く返ってきても、ONEを待って、同時にブラウザに結果表示している。

参考はこちら。
http://stackoverflow.com/questions/15018931/jquery-custom-deferred-functions

jQueryクックブック

jQueryクックブック