座標検索メソッドgetLatLngを同期風に動作させる方法

google Maps APIのジオコーディングメソッドgetLatLngは非同期通信なので色々と面倒です。

サンプルソース1*1

var HogeClass = function
{
	this.get_latLon(address)
	{
		var geocoder = new GClientGeocoder();
		geocoder.getLatLng
		(
			address,
			function(point)
			{
				alert(point);
			}
		);
	}
}
o_hoge = new HogeClass();
o_hoge.get_latLon("京都");

この場合、座標の取得と表示をgetLatLng内で行っているので正常に表示されます。

では表示部分を外に出すとどうなるか

サンプルソース2

var HogeClass = function
{
	this.get_latLon(address)
	{
		var geocoder = new GClientGeocoder();
		var getpoint;
		geocoder.getLatLng //@1
		(
			address,
			function(point)
			{
				getpoint = point; //@2
			}
		);
		alert(getpoint); //@3
	}
}
o_hoge = new HogeClass();
o_hoge.get_latLon("京都");

なんとundefinedが表示されます。

  1. @1のメソッドが実行開始
  2. @2でgetpointにpointの値が代入される
  3. @3getpointを表示

と処理させると思われがちですが、getLatLngは非同期なので実際には

  1. @1のメソッドが実行開始
  2. @3getpointを表示
  3. @2でgetpointにpointの値が代入される

と処理されます。
わぁ!びっくり!*2
この程度の処理なら表示部をgetLatLngメソッドの中に書けばいいだけなのですが、表示部分を別のメソッドでやろうとすると少々大変です。

サンプルソース3

var HogeClass = function
{
	this.point;

	this.get_latLon(address)
	{
		var geocoder = new GClientGeocoder();
		var getpoint;
		geocoder.getLatLng //@1
		(
			address,
			function(point)
			{
				o_hoge.point = point; //@2(thisでアクセスできないので、インスタンス名で直アクセス)
				//evalを使えばハードコーディングしなくても良いのですが割愛
			}
		);
	}

	this.alert_latLon(address)
	{
		this.get_latLon(address);
		alert(this.point); @3
	}
}
o_hoge = new HogeClass();
o_hoge.alert_latLon("京都");

やはり@1→3→2の順に実行され、undefinedと表示されてしまいます。

そこでやっと非同期を同期風に動かす方法

var HogeClass = function
{
	this.point;
	this.timerId;

	this.get_latLon(address)
	{
		var geocoder = new GClientGeocoder();
		var getpoint;
		geocoder.getLatLng
		(
			address,
			function(point)
			{
				o_hoge.point = point;
			}
		);
	}

	this.alert_latLon(address)
	{
		var fnc = function()
		{
			if( "undefined" == typeof(this.point) ) //@2
			{
				alert(this.point); //@3
				clearInterval(this.timerId); //@4
			}
		}

		this.get_latLon(address);
		this.timerId = setInterval(fnc, 100); //@1
		
	}
}
o_hoge = new HogeClass();
o_hoge.alert_latLon("京都");

@1:0.1秒毎に表示用関数を呼びに行く様にタイマーを設定
@2:もし非同期処理の座標取得が完了していれば
@3:表示して
@4:タイマー解除
この方法なら少しの手間で表示メソッドと座標取得メソッドを切り分けた上にオブジェクト指向ライクな書き方ができます。

※注意

サンプルソースは動作確認していません。
脳内コーディングです。
きちんとしたソースで動作確認*3は出来ているので、雰囲気を感じる用としてお使いください。

*1:以下全てのサンプルソースオブジェクト指向でコーディングされていると脳内変換推奨

*2:JavaScriptでは良くあることと言われてしまいました

*3:Firefox3、WindowssafariIE7、IE6