Webエンジニア 新人日記

Webエンジニアになりました。元々はCOBOLやらBASICやらでプログラムしてました。C言語やVisualBasicは趣味でやっていましたが、久々に現場復帰ということです。資格はエンベデッドスペシャリスト、DBスペシャリスト、ネットワークスペシャリスト、セキュリティスペシャリスト、システムアーキテクト、プロジェクトマネージャ他を所有

【Javascript】タイマー処理においてのSetTimeout

GPSロガーをWebアプリで開発

Webアプリで、一定間隔毎になにか処理をさせたいときにはJavascriptを使う。
ところが、これが少し曲者だったりする。

例えば、GPSロガーをWebアプリで実装しようとする。一定時間毎にDBにGPS情報を登録する。
Javascript側でDBに書き込みせずにAjaxで書き込みしようとする。
こちらが実際に書き込みを行う部分

var interval=5000;

var sendgeo = function(){

    if (navigator.geolocation) {
        // 現在の位置情報取得を実施
        navigator.geolocation.getCurrentPosition(
		// 位置情報取得成功時
		function (pos) { 
//取得したGPS情報を画面に書き出す
			var location ="<li>"+"緯度:" + pos.coords.latitude + "</li>";
			location += "<li>"+"経度:" + pos.coords.longitude + "</li>";
			var nDate = new Date();
			location += "<li>"+"時刻:" + nDate.getHours() + ":" + nDate.getMinutes() + ":" + nDate.getSeconds() + "</li>";
//ajaxにて現在地をDBに書き込む
			var data = {
				bus : $('#bus').val(), 
				lat : pos.coords.latitude,
				lng : pos.coords.longitude,
			};

    //Ajax通信メソッド
    //type : HTTP通信の種類(POSTとかGETとか)
    //url  : リクエスト送信先のURL
    //data : サーバに送信する値
			$.ajax({
				type: "POST",
				url: "sendgeo.php",
				data: data,
				dataType: "html",
			//Ajax通信が成功した場合に呼び出されるメソッド
				success: function(html){
					$('#location').html(location);
					$('#result').html(html);
				}
			});				
		},
		// 位置情報取得失敗時
		function (error) {
			var message = "";

			switch (error.code) {
			   // 位置情報取得できない場合
			   case error.POSITION_UNAVAILABLE:
			       message = "位置情報の取得ができませんでした。";
			       break;
			  // Geolocation使用許可されない場合
			  case error.PERMISSION_DENIED:
			      message = "位置情報取得の使用許可がされませんでした。";
			      break;
			  // タイムアウトした場合 
			  case error.PERMISSION_DENIED_TIMEOUT:
			      message = "位置情報取得中にタイムアウトしました。";
			      break;
			}
			window.alert(message);
		});
	} else {
		window.alert("本ブラウザではGeolocationが使えません");
	}
}

この処理を一定間隔で起動するために

$(document).ready(function() {
 var id;

  var setCurrent = function(){
	sendgeo();
	id = setTimeout(setCurrent, interval);
  }
});

setTimeoutで、自分自身を読み出すことで無限ループを実現している。

問題発生

ところが、このスクリプトはPC上ではうまく動くがスマホではうまく動かない。
ログが書き込まれた時刻を見ると、「同じ時刻に数件書き込まれる」
が繰り返され、等間隔に記録されているとは言い難い。

原因

setTimeoutの仕様を調べてみると、「指定された時間が経過したら実行」ではなく
「指定された時間が経過したら実行キューに登録」であった。
そして、実行キューにはいったタスクを実行するタイミングが
おそらくスマホではリアルタイムではなかったということだろう。

実行すると約束したが、いつ何時とまでは約束していないっ......


ってことかな。

ブラウザによる違い

Chromeではhttp通信でGPSを使用できないようになっているようです(Chrome50から)

Xperia Z3(Android 5.0.2)特に省電力設定なし

・標準ブラウザ・・・20秒間隔
Chrome・・・20秒間隔
FireFox・・・最初の数件はリアルタイム 途中から反応なし(プログラムの問題?)
・ドルフィンブラウザ・・・20秒間隔

iPhone7(iOS10.0.1)

Chrome・・・リアルタイム?5秒間隔でもOK
Safari・・・GPSを取得できず