PDA

View Full Version : Ext.data.Storeロード時のloadexceptionについて


Mari
07-15-2009, 08:18 AM
お世話になります。

以下の2点についてご質問させてください。
①Ext.data.Storeのloadexception内で、exceptionとなった原因を判別したいのですが、可能でしょうか?
  (timeoutの場合と、ネットワーク障害などの場合を判別したい。)
②Ext.data.Storeのload実行時にネットワークやサーバー状況などでConnectionが取得できなかった場合、何度かConnectionを取得するようなリトライ機能などはあるのでしょうか?

◆状況詳細
こちらでは、画面初期表示時のonReady内で、Ext.data.Storeを利用してExt.grid.GridPanel にデータを表示しています。

現在、上記動作を実行すると、たまにloadexceptionとなってしまう現象が発生し、原因を調査しているところです。
通常はloadexceptionとならず、正常にデータが取得できていることから、ネットワークの状況などが原因ではないかと疑っています。

そこで、原因を究明するため、loadexceptionでエラー原因などをキャッチしたいのですが、loadexceptionには引数など無いようですし、拾い方がわかりませんでした。

また、ネットワークが原因であった場合、1度であきらめずに何度かリトライしたいのですが、設定方法などございましたら教えてください。

よろしくお願いします。

yuki
07-16-2009, 11:04 PM
APIドキュメントのExt.data.Storeのloadexceptionの箇所は間違っていて、実際にはStoreに設定しているproxyのloadexceptionイベントに渡される引数と同じ物が渡されます。

HttpProxyを利用されているのであれば、

loadexception : ( Object this, Object options, Object response, Error e )

という引数になり、3つ目のresponseの中にstatusというプロパティが入るので、そのコードを見て判断できるかと思います。

リトライについてはStoreそのものに機能はありませんが、loadexceptionの中で判定を行って、必要に応じてloadメソッドを呼び出す等で対応可能かと思います。

ちなみに、Ext JS 3.0ではloadexceptionイベントはなくなり(deprecated)、exceptionイベントに変更となっていますので、2.xを利用されている人は注意してください:s

Mari
07-17-2009, 08:17 AM
お忙しいところ、ご回答ありがとうございました。
ご回答頂きました内容で、こちらで検討してみました。

共通で1箇所修正する方向で行いたいため、Ext.data.HttpProxyをオーバーライドして、以下のように試してみましたが、下記setTimeoutの部分でthisのスコープが問題のようで、エラーとなってしまいます。


/**
* Ext.data.HttpProxy load関数、loadResponse関数 override
* Connectionエラー時リトライ
* 判定方法:response.status=-1(timeout),0(connectionError)
*/
Ext.override(Ext.data.HttpProxy,{
retryCount : 0,
lastOptions : null,
proxyOptions : function(params, reader, callback, scope, arg){
this.lastOptions = new Array(params, reader, callback, scope, arg);
},
load : function(params, reader, callback, scope, arg){
if(this.fireEvent("beforeload", this, params) !== false){
//引数保持
if(this.retryCount == 0){
this.proxyOptions(params, reader, callback, scope, arg);
}
var o = {
params : params || {},
request: {
callback : callback,
scope : scope,
arg : arg
},
reader: reader,
callback : this.loadResponse,
scope: this
};
if(this.useAjax){
Ext.applyIf(o, this.conn);
if(this.activeRequest){
Ext.Ajax.abort(this.activeRequest);
}
this.activeRequest = Ext.Ajax.request(o);
}else{
this.conn.request(o);
}
}else{
callback.call(scope||this, null, arg, false);
}
},
loadResponse : function(o, success, response){
var lastopt = this.lastOptions;
delete this.activeRequest;
if(!success){
if(response.status==0){
// No Connection リトライ
if(this.retryCount < 5){
this.retryCount = this.retryCount +1;
setTimeout(function() {
this.load(lastopt[0],lastopt[1],lastopt[2],lastopt[3],lastopt[4]);
},200);
return;
}else{
// リトライ失敗
this.retryCount=0;//リトライカウント クリア
this.fireEvent("loadexception", this, o, response);
o.request.callback.call(o.request.scope, null, o.request.arg, false);
return;
}
}else{
// timeoutの場合,その他
this.retryCount=0;//リトライカウント クリア
this.fireEvent("loadexception", this, o, response);
o.request.callback.call(o.request.scope, null, o.request.arg, false);
return;
}
}
var result;
this.retryCount=0;//リトライカウント クリア
try {
result = o.reader.read(response);
}catch(e){
// response.status :200の場合
this.fireEvent("loadexception", this, o, response, e);
o.request.callback.call(o.request.scope, null, o.request.arg, false);
return;
}
this.fireEvent("load", this, o, o.request.arg);
o.request.callback.call(o.request.scope, result, o.request.arg, true);
}
});
上記、setTimeout部分の良い解決方法がございましたら、ご教授頂けますと幸いです。
よろしくお願いします。

yuki
07-17-2009, 09:02 PM
setTimeoutの前に、

var that = this;

としておいて、setTimeoutの中で、

that.load(...);

というのが一番シンプルですが、Ext的にやるのであれば、setTimeoutを使わずに、Functionに追加されているdeferメソッドを使って、

this.load.defer(...);

とやるか、もう少し複雑な処理が必要であれば、Ext.util.DelayedTaskあるいはTaskRunnerを使った方が、setTimeoutで生じるスコープの問題を避けることが比較的簡単にできます。

Mari
07-20-2009, 01:46 AM
ご回答ありがとうございました。
deferを使用して、loadを呼び出すことができました。
以下、完成版になります。

/**
* Ext.data.HttpProxy load関数、loadResponse関数 override
* Connectionエラー時リトライ
* 判定方法:response.status=-1(timeout),0(connectionError)
*/
Ext.override(Ext.data.HttpProxy,{
retryCount : 0,
lastOptions : null,
proxyOptions : function(params, reader, callback, scope, arg){
this.lastOptions = new Array(params, reader, callback, scope, arg);
},
load : function(params, reader, callback, scope, arg){
if(this.fireEvent("beforeload", this, params) !== false){
//引数保持
if(this.retryCount == 0){
this.proxyOptions(params, reader, callback, scope, arg);
}
var o = {
params : params || {},
request: {
callback : callback,
scope : scope,
arg : arg
},
reader: reader,
callback : this.loadResponse,
scope: this
};
if(this.useAjax){
Ext.applyIf(o, this.conn);
if(this.activeRequest){
Ext.Ajax.abort(this.activeRequest);
}
this.activeRequest = Ext.Ajax.request(o);
}else{
this.conn.request(o);
}
}else{
callback.call(scope||this, null, arg, false);
}
},
loadResponse : function(o, success, response){
var lastopt = this.lastOptions;
delete this.activeRequest;
if(!success){
if(response.status==0){
// No Connection リトライ
if(this.retryCount < 10){
this.retryCount = this.retryCount +1;
this.load.defer(500,this,lastopt,true); //500msごと10回リロード
return;
}else{
// リトライ失敗
this.retryCount=0;//リトライカウント クリア
this.fireEvent("loadexception", this, o, response);
o.request.callback.call(o.request.scope, null, o.request.arg, false);
return;
}
}else{
// timeoutの場合,その他
this.retryCount=0;//リトライカウント クリア
this.fireEvent("loadexception", this, o, response);
o.request.callback.call(o.request.scope, null, o.request.arg, false);
return;
}
}
var result;
this.retryCount=0;//リトライカウント クリア
try {
result = o.reader.read(response);
}catch(e){
// response.status :200
this.fireEvent("loadexception", this, o, response, e);
o.request.callback.call(o.request.scope, null, o.request.arg, false);
return;
}
this.fireEvent("load", this, o, o.request.arg);
o.request.callback.call(o.request.scope, result, o.request.arg, true);
}
});


今後とも、よろしくお願いいたします。