JSDeferredの基本的な読みかた
JSDeferredを使ったコードを読むときには、
// next() のチェイン
Deferred.next(function () { // 最初の next は Deferred.next
alert(1);
}).
next(function () { // これは Deferred.prototype.next
alert(2);
}).
next(function () {
alert(3);
});
前回すこしばかり例を出しましたが、
Deferred.
このような書きかたを普段しない方のために、
// next() のチェイン
Deferred.next(function () {
alert(1);
}).next(function () {
alert(2);
}).next(function () {
alert(3);
});
読みかたさえ気をつければ、
簡単なアプリケーションを作ってみる
やはり実例がないと理解しずらいと思います。そこで、
- Wikipediaから緯度経度情報をJSONPで取得して
- Google Mapにプロットする
JavaScriptのみで動きますし、
実際のサンプルを見てもらうのが早いかと思うので、
ライブラリ読みこみ
このサンプルを作成する準備として、
<script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="http://github.com/cho45/jsdeferred/raw/master/jsdeferred.jquery.js"></script>
<script type="text/javascript" src="deferred-sample1.js"></script>
ここでは直接ホスト元のを読みこんでいますが、
ここからのコードはdeferred-sample1.
WikipediaからJSONPでデータを読みこむ
「WikipediaからJSONPでデータを読みこむ」
- カテゴリ名からそのカテゴリに属する項目を取得
(JSONP) - 各項目の内容をそれぞれループで取得し、
緯度・ 経度情報を抜きだす (JSONP)
結構な回数をWikipediaにリクエストするので、
とはいえ、
カテゴリ名からそのカテゴリに属する項目を取得
Wikipediaは実はJSONPのAPIを持っているため、
http://ja.wikipedia.org/w/api.php
?format=json
&callback=foobar
&action=query
&list=categorymembers
&cmlimit=500
&cmtitle=Category:%E4%BA%AC%E9%83%BD%E5%B8%82%E3%81%AE%E7%A5%9E%E7%A4%BE
この場合のデータ構造は以下の通りです。
{
"query": {
"categorymembers": [
{
"title": "愛宕神社 (京都市)",
"ns": 0,
"pageid": 450088
},
{
"title": "綾戸国中神社",
"ns": 0,
"pageid": 606892
},
...
まずはここまでをコードにしてみます。
var url = "http://ja.wikipedia.org/w/api.php?format=json&callback=?&action=query&list=categorymembers&cmlimit=500&cmtitle=" + encodeURIComponent(category);
$.getJSON(url).
next(function (data) {
alert(data.query.categorymembers[0].title);
}).
error(function (e) {
alert(e);
});
JSDeferredのjQuery bindingバージョンを読みこんだ場合、
ここではまだ、
各項目の内容をそれぞれループで取得し、緯度・経度情報を抜きだす
さて、
http://ja.wikipedia.org/w/api.php
?format=json
&callback=foobar
&action=query
&prop=revisions
&rvprop=content
&titles=松尾大社|賀茂別雷神社
この場合のデータ構造は以下の通りです。
{
"query": {
"pages": {
"49366": {
"title": "賀茂別雷神社",
"ns": 0,
"revisions": [
{
"*": " .... 内容 .... "
}
],
"pageid": 49366
},
"458561": {
"title": "松尾大社",
"ns": 0,
"revisions": [
{
"*": " .... 内容 .... "
}
],
"pageid": 458561
}
}
}
若干かえってくる構造がわかりにくいです。それはともかく、
var url = "http://ja.wikipedia.org/w/api.php?format=json&callback=?&action=query&list=categorymembers&cmlimit=500&cmtitle=" + encodeURIComponent(category);
$.getJSON(url).
next(function (data) {
var members = data.query.categorymembers;
return Deferred.loop({ end : members.length - 1, step : 35 }, function (n, o) {
var q = [];
for (var i = 0; i< o.step; i++) {
q.push(encodeURIComponent(members[n + i].title));
}
return $.getJSON("http://ja.wikipedia.org/w/api.php?format=json&callback=?&action=query&prop=revisions&rvprop=content&titles=" + q.join("|")).
next(function (res) {
for (var key in res.query.pages) if (res.query.pages.hasOwnProperty(key)) {
var page = res.query.pages[key];
page.revisions[0]["*"].replace(/\{\{ウィキ座標2段度分秒\|(\d+)\|(\d+)\|(\d+)\|N\|(\d+)\|(\d+)\|(\d+)\|E/g, function (_, lat1, lat2, lat3, lng1, lng2, lng3) {
alert([
page.title,
+lat1 + (+lat2 / 60) + (+lat3 / 60 / 60),
+lng1 + (+lng2 / 60) + (+lng3 / 60 / 60)
]);
});
}
});
});
}).
error(function (e) {
alert(e);
});
Deferred.
ループ内部では実際にAPIに投げるクエリを構築し、
- 35ずつ
- 順番に
- 任意の個数の記事を全て
取得することができています。直接緯度経度を取得する方法は著者が確認した限りなかったため、
Google Mapにプロットする
データはひとまず用意できたのでGoogle Mapにプロットしてみます。と、
function CollectLatLongFromCategory (category, callback) {
var url = "http://ja.wikipedia.org/w/api.php?format=json&callback=?&action=query&list=categorymembers&cmlimit=500&cmtitle=" + encodeURIComponent(category);
return $.getJSON(url).
next(function (data) {
var members = data.query.categorymembers;
return loop({ end : members.length - 1, step : 15 }, function (n, o) {
var q = [];
for (var i = 0; i< o.step; i++) {
q.push(encodeURIComponent(members[n + i].title));
}
return $.getJSON("http://ja.wikipedia.org/w/api.php?format=json&callback=?&action=query&prop=revisions&rvprop=content&titles=" + q.join("|")).
next(function (res) {
for (var key in res.query.pages) if (res.query.pages.hasOwnProperty(key)) {
var page = res.query.pages[key];
page.revisions[0]["*"].replace(/\{\{ウィキ座標2段度分秒\|(\d+)\|(\d+)\|(\d+)\|N\|(\d+)\|(\d+)\|(\d+)\|E/g, function (_, lat1, lat2, lat3, lng1, lng2, lng3) {
callback({
title: page.title,
lat : +lat1 + (+lat2 / 60) + (+lat3 / 60 / 60),
lng : +lng1 + (+lng2 / 60) + (+lng3 / 60 / 60)
});
});
}
});
});
}).
error(function (e) {
alert(e);
});
}
リクエストが返ってくる度にマップを更新したいため、
$(function () {
var map = ... Google Map 初期化 ...
CollectLatLongFromCategory(category, function (obj) {
var point = new GLatLng(obj.lat, obj.lng);
var marker = new GMarker(point, icon);
map.addOverlay(marker);
}).
next(function () {
alert('done');
}).
error(function (e) {
alert(e);
});
});
Google Mapの初期化などの解説は省略しましたが、
さて、