Errorの最近のブログ記事

今回は、外部 SWF ファイルを読み込んだ際の、未処理エラーの扱いについての話です。

外部 SWF ファイルの未処理エラー

Loader オブジェクトを使って、外部の SWF ファイルを読み込んだ場合を想定します。このとき、読み込まれた側の SWF ファイル内で未処理のエラーが発生すると、SWF ファイルの階層内でイベントフローが発生します。

例えば、foo.swf が bar.swf を読み込んだとします。その状態で bar.swf 内で未処理のエラーが発生した場合、UncaughtErrorEvent イベントは、それぞれの SWF ファイルの Loader と LoaderInfo オブジェクト間で、以下の順にディスパッチされます。

  1. foo.swf の LoaderInfo (キャプチャフェーズ)
  2. foo.swf 内の Loader (キャプチャフェーズ)
  3. bar.swf の LoaderInfo (ターゲットフェーズ)
  4. foo.swf 内の Loader (バブリングフェーズ)
  5. foo.swf の LoaderInfo (バブリングフェーズ)

これにより、読み込んだ側の SWF ファイル (foo.swf) 内でも、読み込まれた側 (bar.swf) の未処理のエラーイベントを受け取ることができます。

(AS1/2 の SWF ファイルを読み込んだ場合は、UncaughtErrorEvent が発生しません。また、HTMLLoader 内に読み込んだ HTML コンテンツ内での JavaScript エラーも、イベントとして通知されません)

なので、未処理エラーの処理方針として、とりあえずエラーが受け取れればよい、という場合であれば、LoaderInfo にイベントハンドラーを追加するだけで OK ということになります。どの SWF で未処理のエラーが発生しても、最終的にバブリングフェーズで LoaderInfo に通知されるからです。(上のステップ 5)

一方、発生元の SWF ごとに受け取る箇所を分けたい、という場合には、

  • 外部 SWF ファイルを読み込む Loader オブジェクトに UncaughtErrorEvent 用イベントハンドラーを追加
  • そのハンドラー内で stopPropagation() を呼ぶ

とすると、自身の未処理エラーは LoaderInfo、読み込んだ SWF ファイルの未処理エラーはそれぞれの SWF ファイルが読み込まれている Loader、という分け方ができます。

下は、Loader オブジェクトで未処理のエラーを受け取る場合のサンプルです。

ようやく、Flash Player 10.1 の新機能の話です。

前回までは、実行時エラーには、同期/非同期の 2 種類があること、それぞれ catch ブロックまたはイベントハンドラーを使って処理すること、という話でした。

Flash Player 10.1 と AIR 2 からは、「実行時エラーが発生したが catch ブロックにもイベントハンドラーにも渡されなかった」 という状況が起きると、UncaughtErrorEvent が生成されます。これにより、処理されなかったエラーの情報が通知されるため、エラー処理をこまごまと記述しなくても、とりあえずどんなエラーが起きたのかを知ることができます。

とはいえ、同期エラーが起きた場合であれば、スクリプトの実行が途中で終わってしまっている可能性があります。また、非同期エラーだった場合も、エラーの原因となったりソースにアクセスできるとは限りません。

つまり、グローバルエラーハンドラーは、状況を知るのには役立ちますが、それで問題が解決できるかというと、それはまた別の話なのです。アプリケーションが不安定になるようなエラーに対しては、やはり明示的なエラー処理の記述が必要そうです。(あたりまえですが)

UncaughtErrorEvent ハンドラーの追加

さて、UncaughtErrorEvent は、以下の 2 つのオブジェクトからディスパッチされます。

  • LoaderInfo.uncaughtErrorEvents
    SWF 自身のコードによる未処理のエラーを通知
  • Loader.uncaughtErrorEvents
    Loader に読み込んだ SWF 内のコードによる未処理のエラーを通知

どちらのオブジェクトも UncaughtErrorEvents オブジェクトです。UncaughtErrorEvents は EventDispatcher のサブクラスで UncaughtErrorEvent ディスパッチ専用のクラスです。(ディスパッチする側とされる側の違いが、名前の最後の s の有無だけなのです。ややこしい)

良く考えたら、タイトルは 「Flash Player 10.1 と AIR 2 の...」 にすべきでした。

という話は置いておいて、

非同期で行われる処理の場合 (ネットワーク経由のダウンロードとか)、エラーの通知も非同期に行われます。その際、エラーの発生はイベントという手段で通知されます。そのため、非同期エラーの処理は、非同期処理を行うクラスにイベントハンドラーを追加する、という形になります。

非同期エラーを通知するイベントは、以下の 2 種類に分けることができます。

  1. ErrorEvent のサブクラスによる通知
    エラーの種類ごとに提供されるイベントクラスを使用。AsyncErrorEvent、IOErrorEvent など。(一覧はこの 記事の最後にあります)
  2. ステータス通知イベントの属性値による通知
    NetStatusEvent や StatusEvent の属性値を使用。info.level もしくは level 属性の値が error になる。

ネットワーク関連のクラスは、両方の手段を使います。

それぞれ簡単な例を挙げておきます。

ErrorEvent のサブクラスによる通知の例

まず、ErrorEvent の例から。

引き続き、実行時エラーの処理に関する話題です。前回は、同期エラーを捕まえる方法についてでした。

デバッグ用プレーヤーと通常のプレーヤーでの動作の違い

最初に、ちょっと話題が逸れますが、デバッグ用の実行環境を使う際の注意点す。

Flash Professional や Flash Builder をインストールすると、デバッグ用の実行環境が付いてきます。(単独でも入手できます) Flash が表示されている領域で、右クリックしてコンテキストメニューに 「デバッガー」という項目が表示されたら、デバッグプレーヤーがインストールされている状態です。

デバッグプレーヤーでは、エラーが発生した際、通常の実行環境よりも多くの情報を取得することができます。具体的には、以下の 2 点です。

  • Error.getStackTrace() メソッドで、エラーが発生時の呼び出しスタックを取得できる。この属性は同期エラーの場合のみ利用可能。
  • Error.message 属性に、詳細な情報が設定される。通常のプレーヤーでは、大抵は Error.errorID と Error.name 属性の組み合わせの短いテキスト。

他の Error の属性に関しては、どちらの実行環境でも同じになります。

throw 文

では、以下、話を戻して、

スクリプトから、明示的にエラーの発生を通知するには、throw 文を使います。

var myError = new ApplicationError("エラー発生");
throw myError;
 

上のスクリプトが try ブロックで囲まれていた場合、後続の catch ブロックに throw されたオブジェクトが渡されます。下は、その例です。

Flash Player 10.1 から、グローバルエラーハンドラーの機能が追加されました。これにより、未処理のエラーを一括して扱うことが可能になります。

従来は、明示的に処理ロジックの記述されていない Error または ErrorEvent が実行時に発生した場合、その情報を知ることはできませんでした。(デバッグプレーヤーでは、ダイアログボックスが開いてエラーメッセージが表示される) ですが、起こり得る全てのエラーに対して、処理を記述するというのはなかなか面倒かつ困難です。

そこで、Flash Player 10.1 からは、未処理のエラーをまとめて処理できるよう、新しい機能が追加されたというわけです。

実行時エラー処理について

グローバルエラー処理の話の前に、普通のエラー処理についておさらいです。

まず、ここでエラーと言っているのは、実行時に起こるエラーのことです。(例えば、ある URL から swf ファイルを読み込もうとしたら失敗したとか) コンパイル時のエラーではありません。(文法が違ったとか)

ActionScript 3 では、実行時エラーを 2 種類に分けて扱います。

  1. Error クラス (と、そのサブクラス):
    エラーの発生が、実行中のスクリプトから直接扱える場合。関数呼び出しにより起きる実行時エラーはこのタイプ。IOError, TypeError など。
  2. ErrorEvent クラス (と、そのサブクラス):
    エラーの発生が実行中のスクリプトと非同期になる場合。イベントハンドラーで結果を受け取る処理はこのタイプ。IOErrorEvent, SecurityErrorEvent など。StatusEvent などもこれに含める。

上の 2 種類は、それぞれエラー発生の通知のタイミングが、同期/非同期と異なるため、エラー処理の記述も異なります。同期型のエラーの場合は、try..catch..finally を使ってエラー処理を記述します。一方、非同期エラーの場合は、非同期処理を実行するオブジェクトにエラーイベント用のハンドラーを追加します。

(繰り返しになりますが、新しく追加されたグローバルエラーハンドラーは、上記のようなエラー処理の記述されていないエラーを扱うための手段です。同期/非同期どちらのタイプのエラーも扱えます)

try..catch..finally の使い方

さて、ここで、同期エラー処理の基本となる try..catch..finally の使い方について、すこし具体的にします。

try..catch..finally は、エラー発生時の処理を記述するための構文です。エラーが起きると、スクリプトの実行が中断されるため、エラーの起きる可能性のある範囲を try ブロックで囲みます。そして、エラーの起きたときの処理を catch ブロックの中に記述します。catch 文の横には、処理の対象となるエラーオブジェクトの型を宣言します。

2014年1月

Sun Mon Tue Wed Thu Fri Sat
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
レンタルサーバー

月別 アーカイブ

Powered by Movable Type 4.261