IE コンポーネントにおけるイベントの発生順序

一般化しづらいのですがあえて書くと,Navigate(URL) 後の基本的な流れは,こうです。

  1. BeforeNavigate2 イベント発生
  2. NavigateComplete2 イベント発生
  3. DocumentComplete イベント発生
  4. ProgressChange (Progress = 0, ProgressMax = 0) イベント発生(※)

2〜4の間に

  • CommandStateChange イベント
  • DownloadBegin イベント
  • DownloadComplete イベント
  • ProgressChange イベント
  • TitleChange イベント
  • StatusTextChange イベント

が順不同で発生します。

ちょっと複雑な例

アサヒコムのある記事の場合の例ですが,

BeforeNavigate2: http://www.asahi.com/life/update/(略)
NavigateComplete2: http://www.asahi.com/life/update/(略)
BeforeNavigate2: http://pagead2.googlesyndication.com/(略)
NavigateComplete2: http://pagead2.googlesyndication.com/(略)
DocumentComplete: http://pagead2.googlesyndication.com/(略)
DocumentComplete: http://www.asahi.com/life/update/(略)

このように JavaScript で googlead を読み込んでいるのでそれらからもイベントが発生してしまいます。

それじゃ本当の DocumentComplete は?と思いますが,TWebBrowser の LocationURL にドキュメント全体の URL が入っている(そしてブレない)ので,それと比較すれば判定できるかと。


続いて msn の例ですが,

BeforeNavigate2: http://jp.msn.com/
NavigateComplete2: http://jp.msn.com/
BeforeNavigate2: about:blank
BeforeNavigate2: about:blank
BeforeNavigate2: about:blank
BeforeNavigate2: about:blank
BeforeNavigate2: about:blank
BeforeNavigate2: about:blank
BeforeNavigate2: about:blank
BeforeNavigate2: about:blank
DocumentComplete: http://jp.msn.com/
DocumentComplete: http://jp.msn.com/
DocumentComplete: http://jp.msn.com/
DocumentComplete: http://jp.msn.com/
DocumentComplete: http://jp.msn.com/
DocumentComplete: http://jp.msn.com/
DocumentComplete: http://jp.msn.com/
DocumentComplete: http://jp.msn.com/

これも JavaScript で読み込んでいるのですが非常に判断しにくい例です下記追記参照。

最初 iframe 使うとそうなるのかな,と思ったのですが今の msn のページは iframe 使ってないようですし……Ajax で遅延ロードするとこうなるのかなぁ。

BeforeNavigate2 と DocumentComplete の数が対応してないのがちょっと困り者です。


お口なおし?でわかりやすい例として, google.com にアクセスして google.co.jp にリダイレクトされる例です。

BeforeNavigate2: http://www.google.com/
NavigateComplete2: http://www.google.co.jp/
DocumentComplete: http://www.google.co.jp/

NavigateComplete2 の時点でリダイレクト先の URI になっています。サイトによっては BeforeNavigate2 の時点でもリダイレクト先になっていたような……*1

ともかく,この場合 TWebBrowser.LocationURL は http://www.google.co.jp/ になっているのでやはりそちらと比較すればオーケー。

ProgressChange イベントについて

スタート時は ProgressMax が 10000 で,ドキュメントをある程度読み込むまではそのまま Progress がちょっとずつ増えていきます。が,ドキュメント読み込み後は臨機応変に ProgressMax も増えます。なので Progress rate がリニアに増えていくことを期待してはいけません。また,まれに Progress > ProgressMax になるときもありますし。

Progress == -1 の時に読み込み終了,とドキュメントに書いてあります。経験上,上の Step 4 のように(↑※参照),ドキュメントを完全に読み込み終えた時点で Progress = 0, ProgressMax = 0 のイベントが発生するようです(あくまで目安ということで*2)。

NavigationError 発生時のイベント順序

  1. BeforeNavigate2 イベント発生
  2. NavigateError イベント発生
  3. NavigateError イベント発生
  4. NavigateComplete2 イベント発生
  5. DocumentComplete イベント発生

NavigateError がダブっているのは打ち間違いではありません。エラー画面(ドキュメント)を表示する必要があるので,それらの都合で NavigateError イベントが複数回発生することもあります。

しかもエラー画面の表示時に NavigateComplete2 イベント/DocumentComplete イベントが発生するので最終段階だけではエラーとして判断しがたいことがあります。まぁ内的にフラグをもてばいいですし,もっと簡単にはイベントハンドラの Cancel 変数に True を渡すとそこで Navigate 処理が終了するのでその後のイベントは発生しません*3

NavigateError イベントは Status コードを付随しますが,VT_I4(vtInteger)です。サーバサイドのエラーであれば,例えば 404 などのお馴染みのものです。クライアントサイドのエラー(DNS lookup 失敗等)には Status コードは $80000000 みたく 32bit 数値になります。これらについては SDK のドキュメント参照。

このドキュメントのステータスを後から取得する方法がありそうなものですが……みつかりませんでした。DOM 系のプロパティで何かありましたっけ?

結論

ドキュメントを完全に読み込み終えた,と完璧に判断するのは難しいです。下記追記参照。Ajax の場合完全な終わりはありませんし。

プログラマーが読込完了の判断基準を決める必要があります。

追記 2007/09/26

引数pDispがTWebBrowserのApplicationプロパティと一致する場合、そのページは最上位のフレーム(Topのフレーム)であると判定できます。


... snip ...


フレームが使われたページでは、各フレームごとにこのイベントが発生しますが、完了した順に発生するため最上位のフレームは一番最後にこのイベントが発生します。

http://griffy.pekori.to/soft/technologies.html

あーこれでいけました。

*1:301 でローカルにキャッシュされてる場合かなぁ

*2:シンプルに読み込み完了時点を求めるという点では意外に一番いいかも

*3:gmail 等だとエラー時 Cancel := True してしまうときちんと読み込めませんが