最寄駅の時刻表を見て、いちいちNaviTimeやらを使って新宿駅に到着する時間を調べるのが面倒。
そんなニーズに応えるため、この時刻表(最寄駅は変えてあります)のページに細工をして、マウスカーソルを合わせると新宿駅到着時刻が出てくるようにした。
クライアント側ではページロード後に、時刻表から発時刻をサーバーにajaxで送って、新宿駅到着時間を返してもらう。サーバー側では、発駅発時刻を入力すると新宿駅までの経路を判定して文字列を返すPHPスクリプトを書く(実はこっちの方が面倒)。TrainNaviで作ったデータベースをそのまんま使用した。
さて、すべての時間を一気にajaxで問い合わせると、リクエストが200はあるから貧弱な自宅PCが悲鳴を上げそうだ。しかし、asyncをやめて順次問い合わせにすると、ページが表示されるまでとても時間がかかってしまう。というわけで、asyncにしつつ、1つ処理が終わったら次の処理を実行するようなチェーンの仕組みが必要だ。
概念図
処理開始→ajax処理 →ajax処理 →ajax処理・・・
↓ ↑ ↓ ↑
処理終了→↑処理終了→↑
↓ ↓
コールバック コールバック
出来上がったコード(開始駅を変えてあります)
function ktmain(start, end, time, service, cbObj, nextObj){
$.ajax({
async: true,
type: "POST",
url: "ktajax.php",
data: { start : start, end : end, time : time, service : service }
}).done(function( msg ) {
cbObj.callback(msg);
if(nextObj) nextObj.next();
});
}
var KTCallBackObject = (function (){
function KTCallBackObject(dom) {
this.dom = dom;
};
KTCallBackObject.prototype.callback = function(msg){
this.dom.title = msg;
}
return KTCallBackObject;
})();
var KTNextObject = (function (){
function KTNextObject(start, end, time, service, cbObj) {
this.start = start;
this.end = end;
this.time = time;
this.service = service;
this.cbObj = cbObj;
this.nextObj = null;
};
KTNextObject.prototype.next = function(){
ktmain(this.start, this.end, this.time, this.service, this.cbObj, this.nextObj);
}
return KTNextObject;
})();
function MakeMethodChain(base, start, end, service){
var nextObjFirst, nextObjBefore;
for(var i=1; i<=21; i++){
var snum = ("0" + i).slice(-2);
var selector = "." + base + snum;
var root = $(selector);
if(root.size()){
var hour = root.find(".diaHour").html();
var items = root.find("a");
for(var j=0; j<items.size(); j++){
var minute = items[j].innerHTML.replace(/\s| /g,"").substr(0, 2);
var time = hour + ":" + minute;
var cbObj = new KTCallBackObject(items[j]);
var nextObj = new KTNextObject(start, end, time, service, cbObj);
if(nextObjBefore) nextObjBefore.nextObj = nextObj;
if(!nextObjFirst) nextObjFirst = nextObj;
nextObjBefore = nextObj;
}
}
}
return nextObjFirst;
}
function DOMManupilation(){
var start = $("#station-name").find("a").html();
var end = (start == "足柄") ? "新宿" : "足柄";
var mcWeekday = MakeMethodChain("t1-time", start, end, 1);
var mcHoliday = MakeMethodChain("t3-time", start, end, 2);
mcWeekday.next();
mcHoliday.next();
}
$(document).ready(DOMManupilation);
これで、処理終了ごとにktmainがコールされることになり、しかもページの表示を妨げない。実行すると、4時台、5時台、・・・と処理が進んでいって、終電のtitle属性の表示が変わったのは30秒ほど後。やっぱりasyncなしじゃきついね。
サーバー側(開始駅を変えてあります)やっつけ
<?php
require_once 'funcs.php';
$start = $_POST["start"];
$end = $_POST["end"];
$service = $_POST["service"];
$time = $_POST["time"];
if(strlen($time) == 4) $time = "0" . $time;
if($start == "足柄"){
AshigaraShinjuku($service, $time);
}
function AshigaraShinjuku($service, $time){
$mysqli = OpenDb();
$query = "SELECT * FROM tnroute WHERE linename = '小田急小田原線' AND startstation = '足柄' AND endstation='螢田' AND starttime='$time' AND service=$service";
$result = ExecQuery($mysqli, $query);
if($result->num_rows == 0) return;
$row = $result->fetch_assoc();
$trainname = $row['trainname'];
$trainkind = TrainKind($mysqli, $service, $trainname);
$train = Train($mysqli, $service, $trainname);
$dest = $train[count($train)-1]['endstation'];
echo "$trainkind $dest"."行\n";
echo "螢田 $time"."発\n↓\n";
if($dest == "新松田" || $dest == "相模大野"){
$endtime = TimeTrim($train[count($train)-1]['endtime']);
echo "$dest $endtime"."着\n\n";
$trainname = SearchNorikae($mysqli, $endtime, $dest, $service, true);
$trainkind = TrainKind($mysqli, $service, $trainname);
$train = Train($mysqli, $service, $trainname);
$current = $dest;
$dest = $train[count($train)-1]['endstation'];
$loc = StartStation($train, $current);
$starttime = TimeTrim($train[$loc]['starttime']);
echo "$trainkind $dest"."行\n";
echo "$current $starttime"."発\n↓\n";
if(strpos($trainkind, "はこね") !== FALSE)
{
$endtime = TimeTrim($train[count($train)-1]['endtime']);
echo "$dest $endtime"."着\n\n";
echo "(ロマンスカーを使わない場合)\n\n";
$trainname = SearchNorikae($mysqli, $starttime, $current, $service, true);
$trainkind = TrainKind($mysqli, $service, $trainname);
$train = Train($mysqli, $service, $trainname);
$dest = $train[count($train)-1]['endstation'];
$loc = StartStation($train, $current);
$starttime = TimeTrim($train[$loc]['starttime']);
echo "$trainkind $dest"."行\n";
echo "$current $starttime"."発\n↓\n";
}
}
else if($dest == "町田"){
$loc = StartStation($train, "小田急相模原");
if($loc == -1) $loc = StartStation($train, "海老名");
$endtime = TimeTrim($train[$loc]['endtime']);
$new_trainname = SearchNorikae($mysqli, $endtime, "相模大野", $service, true);
if($new_trainname != $trainname)
{
echo "相模大野 $endtime"."着\n\n";
$trainname = $new_trainname;
$trainkind = TrainKind($mysqli, $service, $trainname);
$train = Train($mysqli, $service, $trainname);
$current = "相模大野";
$dest = $train[count($train)-1]['endstation'];
$loc = StartStation($train, $current);
$starttime = TimeTrim($train[$loc]['starttime']);
echo "$trainkind $dest"."行\n";
echo "$current $starttime"."発\n↓\n";
}
else
{
}
}
else if(ExistStation($train, "新松田") && $dest != "成城学園前" && $time != "00:12"){
$loc = StartStation($train, "新松田");
$endtime = TimeTrim($train[$loc]['starttime']);
echo "新松田 $endtime"."着\n\n";
$trainname = SearchNorikae($mysqli, $endtime, "新松田", $service, true);
$trainkind = TrainKind($mysqli, $service, $trainname);
$train = Train($mysqli, $service, $trainname);
$current = "新松田";
$dest = $train[count($train)-1]['endstation'];
$loc = StartStation($train, $current);
$starttime = TimeTrim($train[$loc]['starttime']);
echo "$trainkind $dest"."行\n";
echo "$current $starttime"."発\n↓\n";
}
$endtime = TimeTrim($train[count($train)-1]['endtime']);
echo "$dest $endtime"."着\n\n";
if($dest == "経堂" || $dest == "成城学園前" || ($dest == "町田" && $time == "00:12")){
echo "新宿に着けません";
}
else if($dest != "新宿"){
$trainname = SearchNorikae($mysqli, $endtime, $dest, $service, true);
$trainkind = TrainKind($mysqli, $service, $trainname);
$train = Train($mysqli, $service, $trainname);
$current = $dest;
$dest = $train[count($train)-1]['endstation'];
$loc = StartStation($train, $current);
$starttime = TimeTrim($train[$loc]['starttime']);
echo "$trainkind $dest"."行\n";
echo "$current $starttime"."発\n↓\n";
$endtime = TimeTrim($train[count($train)-1]['endtime']);
echo "$dest $endtime"."着\n\n";
}
}
function TrainKind($mysqli, $service, $trainname){
$query = "SELECT * FROM tntrain WHERE linename = '小田急小田原線' AND trainname = '$trainname' AND service=$service";
$result = ExecQuery($mysqli, $query);
$row = $result->fetch_assoc();
return $row['trainkind'];
}
function Train($mysqli, $service, $trainname){
$query = "SELECT * FROM tnroute WHERE linename = '小田急小田原線' AND trainname = '$trainname' AND service=$service";
$result = ExecQuery($mysqli, $query);
$train = array();
while($row = $result->fetch_assoc()){
$train[] = $row;
}
return $train;
}
function ExistStation($train, $station){
for($i=0; $i<count($train); $i++){
if($train[$i]['endstation'] == $station) return $i;
}
return false;
}
function StartStation($train, $station){
for($i=0; $i<count($train); $i++){
if($train[$i]['startstation'] == $station) return $i;
}
return -1;
}
function TimeTrim($time){
return substr($time, 0, 5);
}
function SearchNorikae($mysqli, $time, $station, $service, $up){
$query = "SELECT * FROM tnroute WHERE linename = '小田急小田原線' AND startstation = '$station' AND starttime>'$time' AND service=$service";
if($up){
if($station == "新松田"){
$query .= " AND (endstation = '渋沢' OR endstation = '本厚木')";
}else if($station == "相模大野"){
$query .= " AND endstation = '町田'";
}else if($station == "町田"){
$query .= " AND endstation = '新百合ヶ丘'";
}
}
$query .= " ORDER BY starttime ASC";
$result = ExecQuery($mysqli, $query);
$row = $result->fetch_assoc();
return $row['trainname'];
}
?>