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

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

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

ブログで色々公開したら、恥をかいたけどすごく勉強になった。

<スポンサーリンク>

f:id:sho322:20140105201031j:plain
http://b.hatena.ne.jp/entry/d.hatena.ne.jp/dropdb/20080115/p1

2日前にsetInterval()を使って、JavaScriptでタイマーで設定した一定時間ごとに動作を繰り返す(定期更新/実行する)サンプルという記事を書きました。

これはsetInterval()が動けばいいや、というかなり稚拙なサンプルだったのですが、たくさんのブックマークをいただきました。
しかし、やはり稚拙は稚拙・・・。

いくつかの「これ、おかしいやろ!」というツッコミをいただきました。

鋭い指摘に唇をかみ、一瞬、「これは恥ずかしい!・・・いっそ消してしまおうか・・・」なんて思ってたんですが、よくよく考えると、プログラミングに関する師匠が周りにいない自分にとって、皆様のツッコミはとても良い指摘となりました。
ありがとうございます。

それで、指摘されたままで何もしなかったら意味がないので、早速勉強してみました。

まずid:serihiroさんにいただいた指摘です。

サーブレット先輩久々に見た

そのココロは、おそらくですが、Web界隈で新しい技術を使っている方々は、いちいちサーブレットみたいなものを書かず、フレームワークで吸収していることを言っているのではないか、それを指して「生サーブレット久々」ということなのではないか、と考えました。

なので、早速本屋に行って買ってきたのが、Play Frameworkの本です。
Play FrameworkはJavaとScalaでRailsっぽくWebアプリを開発できるフレームワークで、サーブレットを使っていません。
serihiroさんが指摘してくれたのはおそらくこのことかと。
そういうわけで、昨日早速勉強してみました。

次に、
id:otchy210さん
の指摘です。

setInterval はサーバ処理が遅れて処理が前後すると色々面倒な事になるので、この用途だったらレスポンス受信後に setTimeout を呼びなおす方がお勧め。あと文字列で function を渡さずに、とか Tomcat のくだりとか、(紙幅足りず)

丁寧な指摘ありがとうございます。
100文字制限なのがもったいない。。

「あと文字列で function を渡さずに」という部分がどうしてもよくわからなかったので、とりあえずsetTimeoutを勉強してみました。
こちらは、最後にサンプルを書いてみようかと思います。

なお、setTimeout()は以下を参考にしました。
http://stone.moo.jp/JavaScript-WorkBook/workbook/s28.html

最後に、
id:uxlayman

いやこれサーバーと同期してなくて何のためにajax使ってるのかw サーバー側コードも複数クライアントからアクセスしてちゃんと動くのかな?

すいませんすいません・・・、ajaxの意味なかったです。

複数クライアントからアクセスしたら前のサンプルではcountは意味をなしません。

完全にsetInterval()を動かすことだけ考えてました。

ご指摘ありがとうございます。

で、こちらについては、セッションIDをサーバ側で保持してみようと考えました。

その記事がこちらです。
Play FrameworkでセッションごとにIDを割り振り、サーバで保持して、ブラウザに表示してみる。

でも、セッションごとにリクエスト回数を保持する方法がちょっとよくわからなかったので、これは保留して勉強を進めてみます。
たぶん1ヶ月後にはわかるようになってるはずと信じて・・・!

最後に、id:C_Lさんから投げ銭をいただきました!

さて、昨日から勉強した結果で、サンプルを作ってみます。

ここから先はコードがあって面白くないと思うので、先に言っておきます。
皆様、ご指摘ありがとうございました!

ブログやっててよかった。

「ブロガーなら公開して恥をかけ、馬鹿め」

というのは本当ですね。

ここからはいつもの口調でw


※下の方に大切な追記があります※

Play Framework上で、setTimeout()を使って、タイマーで設定した一定時間ごとに動作を繰り返す(定期更新/実行する)サンプル


まず、POSTリクエストを投げるJavaScript.
sample.js

$(function() {
	var timerId = null;
	var jsonData = null;
	$("#startBtn").click(function() {
		var name = $("#input").val();
		jsonData = {
				'input' : name
		};
		update();
	});

	function update() {
		$.post("/ajax",
				jsonData,
				function (res) {
					var session = "SESSION ID:" + res.session;
					var myName = "MY NAME:" + res.name;
					$("#result").append(session + "   |||   " + myName + "<br/>");
					//timerId = setTimeout('update()',1000);
					timerId = setTimeout(function(){
						update();
					}, 1000);
				}
			);
	}

	$("#stopBtn").click(function() {
		clearTimeout(timerId);
	});
});

ここのsetTimeoutが今回の最大のポイントで、繰り返し実行するには再帰処理を行う必要がある。
つまり、function update()内で呼び直すことで、時間差で繰り返すことができる。
今回は1000ミリ秒、つまり1秒おきに繰り返してみた。

で、こいつをindex.scala.htmlで読み込む必要がある。
こんな感じで書けばいい。

@(msg: String)

@import helper._
@import helper.twitterBootstrap._
@main("Sample Page") {
	<script src="@routes.Assets.at("javascripts/sample.js")"
		type="text/javascript"></script>
	<h1>setTimeout()のサンプル</h1>
	<input type="text" id="input">
	<button id="startBtn">通信スタート</button><br/>
	<button id="stopBtn">通信ストップ</button>

	<hr/>
	<div id="result"></div>
}
	<script src="@routes.Assets.at("javascripts/sample.js")"
		type="text/javascript"></script>

の部分で、sample.jsを読み込んでくれる。

リクエストは/ajaxに投げてるから、
routesファイルを編集して、以下を追記する。

POST  /ajax                       controllers.Application.ajax()

で、受ける側の処理。
controllerのApplication.javaはこんな感じになる。

package controllers;

import org.codehaus.jackson.node.ObjectNode;

import play.data.Form;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;
import views.html.index;

public class Application extends Controller {

	public static Result index() {
		String uuid=session("uuid");
		if(uuid==null) {
		    uuid=java.util.UUID.randomUUID().toString();
		    session("uuid", uuid);
		}
		return ok(index.render("UserID:" + uuid));
	}

	public static Result submit() {
		String name = Form.form().bindFromRequest().get("name");
		String myId = session("uuid");
		return ok(index.render("リクエスト受け取った!貴様の名前は→" + name +"だな!?" + "セッションIDは:" + myId + "だッッ!"));
	}

	public static Result ajax() {
		String name = request().body().asFormUrlEncoded().get("input")[0];
		String sessionId = session("uuid");
		ObjectNode result = Json.newObject();
		if (name == null || name == "") {
			result.put("session", sessionId);
			result.put("name", "名前いれろや!!");
			return ok(result);
		} else {
			//result.put("session", sessionId);
			result.put("session", sessionId);
			result.put("name", name);
			return ok(result);
		}
	}
}

submit()メソッドは関係ないですw別のサンプルに使ったやつです。
今回使っているのはajax()メソッドのところ。
クライアントからのJsonデータを受け取って、セッションIDを入れてJsonで返している。

さて、実際にブラウザで開いてみると・・・
f:id:sho322:20140105201242j:plain

こんな感じでセッションIDと名前が1秒おきに表示することができた。
ちなみに、「通信ストップ」ボタンを押すと、setTimeout()を止めることができる。


※重要※
【追記】
id:otchy210さんが上記のJavaScriptを添削してくださいました。

特に、コストが高いjQueryオブジェクトの生成を抑え、ボタン連打の抑止、triggerの使い方がとても参考になりました!!

「ブログで色々公開したら、恥をかいたけどすごく勉強になった。」の添削

本当にありがとうございます!!

ちなみにですが、以下の記事にもお礼を書かせていただきました。
情熱プログラマー「一番の下手くそでいよう」に思うこと。
【追記ここまで】

エラー対応

ちなみに、

timerId = setTimeout('update()',1000);

と書いたら、以下のようなエラーが出たので、以下を参考にして解決しました。

update is not defined setTimeout

http://maxura.blog62.fc2.com/blog-entry-179.html

timerId = setTimeout(function(){
	update();
}, 1000);

って書かなければいけないみたい。