y-matsui::weblog

電子楽器、音楽、コンピュータ、プログラミング、雑感。面倒くさいオヤジの独り言

非同期リッチクライアントとJavascriptの作法についての覚書

Javascriptデバッグにはいつも苦労する。標準のデバッグメッセージでは不十分なのと、VisualStudioのデバッガを使ったとしても誤爆するからだ。誤爆の原因は、JavascriptVBScriptJScriptなどの様々なスクリプト、DOM、ActiveXなどの複数の要素が複雑に絡み合うからである。
YUIGoogleなど公開されているAPIや、フリーのAjax,Javascript部品を使うケースが今後ますます増えていくので、Javascriptの作法を整理しておかないとやばい。
今回分かったのは、ブラウザ内オブジェクトの生成順と、プログラム実行タイミングの制御をしていないと、とたんにバグとして出てくる例。

■現象
左フレームにXML-DOMを展開するフォルダツリーメニュー
右フレームにDataBIND(ActiveX)でコンテンツデータを読む込むデータグリッドを配置
操作は当然、左フレームでフォルダ階層を選択して、右フレームのコンテンツを検索するのであるが、Javascript+HTMLツリーをXMLツリーに変更したとたんに、エラーが出た。
「オブジェクトは、このプロパティまたは メソッドをサポートしていません」
むむ?Javascriptがフレームをまたがったオブジェクトのメソッドにアクセスできなくなっちゃった?
その割には、一度ロードした後の実行では全くエラーが出ない。(正常)

■あれこれやってみる
・XMLTreeを生成するオブジェクトで、XMLLoadをコメントアウトするとエラーが出ない
別フレームのメソッドを実行する部分をコメントアウトするとエラーが出ない
別フレームのメソッドがActiveXオブジェクトを生成するからか?とも疑うが、デバッガは反応していないのでバグではなさそう。
XMLオブジェクトで、XML読み込みを非同期ではなく、同期にしてみるが、今度はツリーが表示されなくなる。
・一度XMLTreeとお別れし、これをJSONツリーに変更すると、エラーが出ない。

■解決策
「個々のプログラムは悪くない。タイミングで発生する」と仮定。←大正解!!
例:左フレームのツリーから右フレームに検索条件を与え、検索を実行するプログラム
プログラムの実行前に条件を判定する部分

変更前   (右フレームに表示されているコンテンツ名のみを判定)
if (lochtml.match("mainsearch.html")){
                             ↓
変更後   (表示されているコンテンツ名と読込み済みをあらわすフィールドの値で判定)
if *1&&(parent.body.document.getElementById("load_flag"))){

右フレームのコンテンツの末尾に隠しフィールド”load_flag”を付け加え、これがgetElementByIdで見つかれば、それ以前のフィールドは生成が完了しているはず・・という理屈。

■結論
データ読み込み完了、描画タイミング、プログラム実行タイミングの組み合わせで発生している問題であると判明。(なぜなら、初回起動時しかエラーが出ない、その後個別のフレームを再読み込みしてもエラー状態が再現されない)
ブラウザに大量のデータやスクリプトを食わせてやる仕組みになればなるほど、また非同期実行が一般的になればなるほど、ページ読み込み完了やプログラム初期化完了などのステータスを厳密に管理してやらないといけなくなる。
※もしかして、すべての操作対象オブジェクトに対してgetElementByIdで検索して存在を確認しなきゃいけないとか?←オブジェクトがあるという想定ではなく、無いという想定でスクリプトを書く?

■参考
「そもそもイベントは色々定義されていないのだろうか?」と思って調べてみる。
onLoadは、全部のソースを読み込んだ後に発生するので、onLoadイベント以降に全オブジェクトを初期化するようなメタ関数をかませれば良さそうな気もする。
IEでは○○とかMozilla系では△△とか・・やっぱり面倒くさそう
ねこめしにっきにこのあたりの悩ましい話が載っていた。
ブラウザ内オブジェクトの実行順制御って、すごく面倒臭そうな問題を抱えている気がしてしょうがない。

*1:lochtml.match("mainsearch.html"