Ajaxの価値とは
Ajaxブームもそろそろ下火になってきたと思います。「なぜか?」から「どうしたら?」まで考えてみました。
※記事を載せる時間すら減ってはいますが、通勤時間などでJavaScript・Ajaxなどに関して考える時間はあるので、ここでその間に考えたことをメモしておきます。
一般にWebに公開されているAjaxアプリと呼ばれるものはどんなものがあるかと思い浮かべてみたいと思います。
こんな感じでしょうか。本当はまだまだあるとは思いますが、とりあえずすぐ思いつく程度で軽い分析には十分です。
これらを参考に、
「そもそもどうしてAjax*1が有用なのか」
を考えると、それはつまり
「どうして一部だけサーバーで処理するのか?」
という疑問になります。
もちろん「全部をサーバーで処理する」とはしない*2でしょうから、
「なぜ、全部をクライアントで処理しないのか」
を考えてみます。
例えば上に挙げた中から考えると以下の理由がわかります。
- データはサーバーに置き、必要な分を必要なときに渡すため。
- (クライアントで全部処理するには)ベースとなるデータ量が膨大である。
- なおかつ、そのデータのごく一部にしかアクセスしない。
- 1つ1つのデータはわりと軽いものである。
- 処理を高速化するため。
- サーバーの方が処理速度がダントツに速い。
- ユーザーのトリガーを受けてから戻るまでの間、業務的な処理の割合が高い。
- 通信時間を差し引いてもサーバーで処理する方が速い。
- 処理内容・方法を隠蔽するため。
- 直感的な操作は欲しいが、肝心な業務処理の方法は公開したくない。
さて、理由(≒Ajaxのメリット)が整理できたところで、
「どうしたらAjaxを使ってウケるサイトを作れるか」
を考えてみたいと思います。
・・・と言っておきながら、この考え方は間違っていると思います。
Ajax*3は単なる技術的な手段です。
それが見直されただけであり、例えばJAVAでいう
「SWING*4を使って何を作ろうか」
と考えているようなものです。
本当はその逆で、
「○○○ということをしたいのだけれど、どんな手段で実現しようか」
を考え、その手段の1つとしてAjaxがあるはずです。
では、考え方を修正して
「Ajaxが有効な手段として考えられるサービスは何か」
と考えなければなりません。
Ajaxが有効な手段となるケースとは、上記で整理していますから、それに当てはまる“○○○”を考えることになるでしょう。
例えば以下のようなもの*5はどうでしょうか。
- 時刻表検索
- データ量が膨大であるのに、参照するデータはごく一部のみ。
- 最初のルート検索などでアルゴリズムが売りの場合は、隠蔽できる。
- 検索結果から再検索しても、画面レイアウトはほとんど変わらない。
- 参照先の再検索(1本前の時間検索とかする)の対象となるデータ幅が狭い。
- 付近のデータで、再検索されそうなデータをアイドル時間に予め読み込んでくれると瞬時に表示可能。
- 検索結果がGUI操作できると新鮮。
ただ、これだと誰でも考えつきそうですね。
誰も考えたことがないような「こんなこともできるのか!」を世に出すためには、上記の“××系”を新しく増やす必要があると思います。
これは結構難しいですが、その分他人には思いつかれにくいでしょう。
私は××系とかカテゴリーを考えずに、“○○○”(前述)を考えていますが、ほとんど既存の××系にあてはまってしまいます。
つまり、結論としては、
「検索系でも、変換系でも、画像系でも、計算・処理系でもない、Ajaxのメリットに合致するWEBサービスを考えよ」
となるでしょう。
本家サイトを更新しなきゃ・・・
本来のサイト「新しいJavaScriptの使い方」を更新しなきゃしなきゃと思いつつもできていない。
ブログと違って文章をきちんと考えるのが結構辛いものがある。
それと、ネタも。
JavaScriptクイズのネタないかなぁ〜と思うのだけれども、どれもこれも「簡単かな」と思えてきちゃう。*1
掲載に向けて要努力のネタ*2
- 展開ツリースクリプト⇒+と−でツリーを展開&収納
- TellMotion⇒ユーザーに対し何らかのメッセージを伝えるモノ
- StackTrece.js⇒エラーのスタックトレース可能なおまけ
- 名称未定⇒フォームをラップして、送信直前の状態をウォッチするツール
- FormViewer.js⇒フォームを検査して、値や状態の表示と設定ができるツール
仕事でJavaScriptができたらいいんだが、そうもいかない。
JScriptコンソールの実践的な使い方
以前に書いたJScriptコンソールですが、意外とアクセスがあるようなので、私がやっている実践的な使い方を載せたいと思います。
※(前提)以前に紹介したJScriptのファイルを、console.jsとします。
※(注意)一部のフォルダ・ディレクトリを***とさせていただいております。
ポイントはWSFファイルを作ることです。
私の場合は、(今の段階では)以下のように作っています。
<job id="main">
<script language="JScript" src="***\CPT.js" charset="Shift_JIS"></script>
<script language="JScript" src="***\ClassLoader4WSH.js" charset="Shift_JIS"></script>
<script language="JScript" src="***\JavaScriptDocument.js" charset="Shift_JIS"></script>
<script language="JScript" src="***\JavaScriptLogger.js" charset="Shift_JIS"></script>
<script language="JScript" src="***\JavaScriptErrorManager.js" charset="Shift_JIS"></script>
<script language="JScript">
this.setIncludeBase("***/ClassPackagingTool/");
js.debug.jsd.setIncludeBase("***/JavaScriptDocument/js/debug/jsd/");
js.debug.log.setIncludeBase("***/JavaScriptLogger/js/debug/log/");
js.debug.jsem.setIncludeBase("***/JavaScriptErrorManager/js/debug/jsem/");
include("js.debug.jsd.*", true);
include("js.debug.log.*", true);
include("js.cpt.*", true);
js.cpt.Error.cast2NativeError = true;
include("js.debug.jsem.*", true);
</script>
<script language="JScript">
function displayInclude(obj, prefix) {
if(!obj) {
write("");
return arguments.callee((function(){return this;})(), "");
} else if(!prefix) {
prefix = "";
}
for(var i in obj) {try{
if(((typeof obj[i]) == "function") && prefix && obj[i].Static) {
plusln(prefix + i);
} else if(obj[i] instanceof js.cpt.Class) {
plusln(prefix + i + " - !");
} else if(obj[i] instanceof js.cpt.Package) {
plusln(prefix + i);
arguments.callee(obj[i], (prefix + i + "."));
}
}catch(e){}}
}
</script>
<script language="JScript" src="console.js" charset="Shift_JIS"></script>
</job>
これにより、JScriptコンソールが起動する前に、そのコンソールで使用できるクラスやメソッド,変数などを用意しておくことができます。私はCPTパッケージを使ってJavaScriptDocument,JavaScriptLogger,JavaScriptErrorManagerの各パッケージを読み込み、関数displayIncludeを定義してからJScriptコンソールを起動しています。
また、console.jsもこのWSFファイルもダブルクリックで起動すると(デフォルトでは)WScriptで起動されるのですが、その場合はconsole.jsがCScriptで起動しなおすように作られています。そもそも“コンソール”ですからCScriptで起動する必要があり、WSFファイルの事前準備を無駄にしないためには、WSFファイル自体をCScriptで起動します。
それには、以下のような簡単なバッチファイルで実現できます。
@echo off
CScript //Nologo 上記で作ったWSFファイル
これを実行(ダブルクリック可)すると、万事OKというわけです。
document.open()でスコープチェーンが破壊される?
私はローカルPCにJavaScriptの調査や実験結果によってわかったテクニックや情報をいろいろと保存しています。忘れた頃に「なんだったっけなぁ〜」と思いながら探すためです。
今日は、なんとなくフォルダの下を眺めていたら、
「document.open();によるスコープチェーンの破壊.txt」
なるファイルがあるじゃないですか!!非常に興味をそそられ(本当は昔に自分が作ったはずなのに)中身を見てみると以下のように書いてありました。
document.open();
すると、スコープチェーンが破壊されるようだ。
例えば...
・関数Aを用意
・その中でdocument.open();
・関数Bを用意
・その中でsetTimeout(自分の参照);
・関数Cを用意
・その中で、AとBを呼ぶ。
→結果
・Aで破壊されるが、Cの中ではBの参照はまだ持っている。
・Bも1回目は呼ばれる。
・だが、タイマーで自分を呼ぼうとしたとき、解決できない。
※document.open();がなければ、この現象は発生しない。
これを読んでもまだ思い出せませんでした。
そこで、れっつ実験!
<html>
<head>
<script type="text/javascript"><!--
// 関数A
function funcA() {
alert("Start funcA!");
document.open();
alert("Exit funcA.");
}
// 関数B
function funcB() {
alert("Start funcB!");
setTimeout(funcB, 0);
alert("Exit funcB.");
}
// 関数C
function funcC() {
alert("Start funcC!");
funcA();
funcB();
alert("Exit funcC.");
}
//funcC();
//--></script>
</head>
<body>
<div style="cursor:pointer;" onclick="funcC();">START</div>
<div style="cursor:pointer;" onclick="funcB();">FUNC_B</div>
</body>
</html>
⇒感想(その1)「あたりまえじゃん」
document.open();すると、今までの内容を破棄して新しく何かしようとするわけですよね。
⇒感想(その2)「ちょっとおもしろいけど、あんまり使わないなぁ」
scriptの閉じタグ直前の//funcC();をコメント外し、funcBの中のタイマーの時間を数秒くらいにして実行してみました。つまり、ファイルを読み込み途中でdocument.open();しても平気なんですね。
それに、よくよく考えると、(元のSTARTボタンで実行する場合に)document.open();したあとのソースも実行していますね。もしこれがlocation.replace("about:blank");などで画面遷移させたら、その直後からソースは実行されない*1はずです。
ふぅ〜む・・・と思ったところらへんで「そういえば半年か1年くらいまえに調査したかなぁ」とうっすら思い出しました。
【注意】なお、この件に関しては、本当にスコープチェーンが破壊されたからfuncBが実行できなくなったのかどうかという原因については、私の完全なる憶測です。ご注意ください。