2011年6月21日火曜日

try...catchとErrorオブジェクト

基本的なtry...catchの書き方
try {
    // Code
} catch (varName if condition) { // Mozilla extension; optional
    // If exception thrown which matches condition
    // in try block, execute this block
} catch (varName) {              // Optional
    // If exception thrown in try block,
    // execute this block
} finally {                      // Optional
    // Execute this block after
    // try or after catch clause
    // (i.e. this is *always* called)
}
Firefoxはcatch内でifを使う特殊な書き方ができる。
コード全体をtry...catchしたいーなんて思ったときはwindow.onerrorを使った方がいい
サイ本にもwindow.onerrorを使ったエラーキャッチ(回数制限つける)するものが書いてあった。
// Display error messages in a dialog box, but never more than 3
window.onerror = function(msg, url, line) {
    if (onerror.num++ < onerror.max) {
        alert("ERROR: " + msg + "\n" + url + ":" + line);
        return true;
    }
}
onerror.max = 3;
onerror.num = 0;
いつtry...catchするか、という話が結構難しい感じがする。
JavaScriptだとファイルを読み込むとか、メモリを解放するとかそういう話を直接扱うことはまだ余りないので、使いどころが何か難しいし、いろん なところでwithなどと一緒にパフォーマンスを悪くする要因と書かれたりするので、全くtry...catchしてないコードもよくある。
使うべき所の一つとしてはtry~catch文の正しい使い方 - 素人がプログラミングを勉強するブログを見ていて思ったけど、XPathはなぜか静かに死ぬことがあって、そういう時はどこが悪いのかを見つけるのが大変になるので、エラーハンドリングが大事。 というのも、XpathをGreasemonkeyでのスクレイピングでよく使っていて、サイトの仕様変更によってそのXPathが間違いになる事があって原因究明が大変だった体験などもあるので、経験則的にXPathは気を遣う。
(それ以前の話としては、普通のWebサイトではtry~catch文の正しい使い方のようにユーザー入力を直接セレクタに使うのはnew XSS pattern with jQueryのように危険な場合があるので、try...catchしようがやめておいた方がいいと思うけど)

try...catchが使いにくいって思うのには、どれが例外を発生するかを知っておく必要があるところが大きい気もする。
後、普通にコードを書いて例外が発生しても、それはtry&error方式で直せるのであえてtry...catchするのは避けてしまう。
なので、ユーザーの入力値を元にするもの、外部サイトAPIなどの変更可能性が存在する場合、エラーが発生しても握りつぶしておきたい場所、など使われる場所はある程度決まってくるような気もする。
try...catchの経験不足なので、まだ使いどころをあげきれない。
完全に余談だけど、try...catchを書くときに、後からtry...catchを書き足して囲むみたいな事になる場合が多くて、そういう時にWebStormのSurround With...が便利。
Errorオブジェクト
また、try~catch文の正しい使い方の話に戻るけど、try...catchで黙ってエラーをつぶすとデバッグが大変なので、自発的にthrowをしてエラーを投げた方がいい。catch内でthrowする場合はErrorオブジェクトがあるので、それをthrowするだけでいいけど。
下のように、try...catch以外の場所でthrowする場合はerrorオブジェクトを作ってそれを投げた方がいい。
function dosomething(arg){
    if(!arg){
        throw new Error("引数がありません");
    }
}
というのも、throw "文字列"; などのようにErrorオブジェクトじゃないものもthrowできるけど、デバッガーなどに渡す情報に行番号などがないので、errorオブジェクトを作って投げた方がデバッグしやすい。
おまけ: try...catchのスコープについてなど

0 コメント:

コメントを投稿