hifiveにおける例外処理
例外処理
hifiveでは、例外が発生したときの処理を記述できる機構を用意しています。
commonFailHandler
h5.settings.commonFailHandlerは非同期処理が失敗した時に実行されます。デフォルトはnullで、関数を設定すると動作します。
ただし、非同期処理が失敗した時にfailハンドラが登録されていた場合は動作しません。非同期処理が失敗した時に動作するハンドラが登録されていない場合に、commonFailHandlerが『共通のfailハンドラ』として実行されます。
また、commonFailHandlerはh5.async.deferred()及びh5.ajax()などのhifiveのメソッドを利用した非同期処理が失敗した場合に呼ばれます。$.Defferd()や$.ajax()を使用した場合はcommonFailHandlerは実行されません。
h5.settings.commonFailHandler = function(){
// 非同期処理の共通のfailハンドラとして動作する。
// 引数及びthisは失敗した非同期処理のfailハンドラの引数及びthisになる
console.log('commonFailHandler!');
}
// ----------------------
// h5.async.deferred()
// ----------------------
var dfd = h5.async.deferred();
dfd.reject(); // commonFailHandler!
var dfd2 = h5.async.deferred();
var promise2 = dfd2.promise();
promise2.fail(function(){
// 登録されたfailハンドラ
});
dfd2.reject(); // failハンドラが登録されているのでcommonFailHandlerは実行されない
// ----------------------
// h5.ajax()
// ----------------------
h5.ajax('noExistPage'); // 'commonFailHandler!'
h5.ajax('noExistPage').fail(function(){}); // failハンドラが登録されているのでcommonFailHandlerは実行されない
h5.ajax('noExistPage', {
error: function(){}
});
// errorによってエラー時のコールバックが登録されているのでcommonFailHandlerは実行されない
h5.ajax('noExistPage', {
complete: function(){}
});
// completeによってエラー時のコールバックが登録されているのでcommonFailHandlerは実行されない
エラー時のコールバックが登録されていた場合にはcommonFailHandlerは実行されません。failメソッドに限らず、alwaysやthenでエラー時に動作するハンドラが登録されていた場合も、commonFailHandlerは動作しません。
var promise3 = dfd3.promise();
promise3.always(function(){
// alwaysを使ってdoneハンドラとfailハンドラを登録
});
dfd3.reject(); // failハンドラが登録されているのでcommonFailHandlerは実行されない
var dfd4 = h5.async.deferred();
var promise4 = dfd4.promise();
promise4.then(function(){
// thenから登録したdoneハンドラ
}, function(){
// thenから登録したfailハンドラ
});
dfd4.reject(); // failハンドラが登録されているのでcommonFailHandlerは実行されない
var dfd5 = h5.async.deferred();
var promise5 = dfd4.promise();
promise5.then(function(){ // 第2引数を省略してdoneハンドラだけ登録
// thenから登録したdoneハンドラ
});
dfd4.reject(); // 'commonFailHandler!'
h5.async.when()を使用した時のcommonFailHandlerの動作
when()で実行した非同期処理に対してfailコールバックを指定していない場合で、when()に渡したいずれかのプロミスに基づく非同期処理が失敗したときは、when()による非同期処理についてのcommonFailHandlerが動作します。
when()の引数に渡した各プロミスに基づく非同期処理についてのcommonFailHandlerは動作はしません。
var dfd2 = h5.async.deferred();
var dfd3 = h5.async.deferred();
var whenPromise = h5.async.when(dfd1.promise(), dfd2.promise(), dfd3.promise());
dfd1.reject(); // when()による非同期処理が失敗し、whenPromiseにfailハンドラが登録されていないので、commonFailHandlerが動作する
dfd2.reject(); // commonFailHandlerは動作しない
dfd3.reject(); // commonFailHandlerは動作しない
when()に対してfailハンドラを登録した場合はcommonFailHandlerは実行されません。
var dfd2 = h5.async.deferred();
var dfd3 = h5.async.deferred();
var whenPromise = h5.async.when(dfd1.promise(), dfd2.promise(), dfd3.promise());
whenPromise.fail(function(){
console.log('when fail');
});
dfd1.reject(); // 'when fail' commonFailHandlerは実行されない。
dfd2.reject(); // commonFailHandlerは実行されない。
dfd3.reject(); // commonFailHandlerは実行されない。
when()に渡されたプロミスは、失敗した時にwhen()のfailハンドラを呼ぶ、というエラー時の処理が追加されます。commonFailHandlerはfailハンドラが登録されていない(=エラー時に何もしない)非同期処理に対して動作するので、when()に渡されたプロミスについての非同期処理が失敗してもcommonFailHandlerは動作しません。
ただしwhen()自体が実行する非同期処理については、failハンドラを登録されていない場合にcommonFailHandlerが動作します。
errorInterceptor
アスペクトを利用して例外を処理する方法を紹介します。
hifiveでは、h5.core.interceptor.errorInterceptorは「例外が発生するとcommonFailHandlerを実行するインターセプタ」を用意してあります。このインターセプタを使って、コントローラやロジックに対してアスペクトを掛けることで、commonFailHandlerで例外処理をすることができます。この方法は同期で例外が発生する場合に有効です。
$(document).bind('h5preinit', function() {
var aspects = [];
aspects.push({
target: '*',
interceptors: h5.core.interceptor.errorInterceptor,
pointCut: '*'
});
h5.settings.aspects = aspects;
});
アスペクトの掛け方についてはこちらをご覧ください。
チュートリアル(基本編) » 12.AOP(アスペクト)の適用
例外が発生すると、commonFailHandlerが実行されます。
console.log(e.message);
}
h5.core.controller('body', {
__name: 'SampleController',
__init: function(){
throw new Error('error interceptor test'); // commonFailHandlerにエラーオブジェクトが渡される
}
});
errorInterceptorの詳細についてはAPIドキュメントをご覧ください。
JSDoc: h5.core.interceptor.errorInterceptor
window.onerror
window.onerrorはJavaScriptでエラーが起きた時に呼ばれるイベントです。window.onerrorに関数を登録すると、JavaScriptでエラーがあった時に関数が実行されます。tryブロックでエラーが発生した場合は実行されません。
※Android3以下、iOS4以下ではwindow.onerrorは動作しません。
console.log('window.onerror! ' + errMsg);
};
noexistfunc(); // window.onerror! Uncaught ReferenceError: noexistfunc is not defined
try{
noexistfunc(); // window.onerrorは実行されない
} catch(e){
}
同期、非同期に関わらず、try-catchで囲んでいない(想定していない)例外を全て処理したい場合に有用です。