Ajax.Requestクラス(2)
respondToReadyStateメソッド
【抜粋】 respondToReadyState: function(readyState) { var event = Ajax.Request.Events[readyState]; var transport = this.transport, json = this.evalJSON(); if (event == 'Complete') { try { (this.options['on' + this.transport.status] || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] || Prototype.emptyFunction)(transport, json); } catch (e) { this.dispatchException(e); } if ((this.header('Content-type') || '').match(/^text\/javascript/i)) this.evalResponse(); } try { (this.options['on' + event] || Prototype.emptyFunction)(transport, json); Ajax.Responders.dispatch('on' + event, this, transport, json); } catch (e) { this.dispatchException(e); } /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ if (event == 'Complete') this.transport.onreadystatechange = Prototype.emptyFunction; },
respondToReadyStateメソッドを呼び出すのは、onStateChangeメソッドか、requestメソッド内ののsetTimeout関数です。つまり、1:Loading以外のonreadystatechange時と、インスタンス作成の0.01秒後になります。
引数readyStateには、その時点のXMLHttpRequestのreadyStateプロパティの値が設定されます。ただし、setTimeout関数から呼ばれた場合はreadyStateプロパティの値にかかわらず、1(Loading)が設定されます。
変数eventに引数に対応するイベントを表す文字列、変数transportに自オブジェクトのXMLHttpRequest、変数jsonに、前述evalJSONメソッドを使用して、X-JSONヘッダの実行結果を格納します。*1
変数eventが'Complete'(通信完了)のとき、まずoptionsプロパティのオブジェクトに、"on"+(その時点のXMLHttpRequestのstatusプロパティの値(=HTTPステータスコード))に該当するメソッドがあればそれを実行します。該当メソッドがない場合、Ajax.Baseから継承したresponseIsSuccessメソッドにより通信の成否を判定し、成功時にonSuccessメソッド、失敗時にonFailureメソッドがあれば実行します。これもない場合はPrototype.emptyFunctionを実行します(つまり何もしない)。引数はいずれも変数transportと変数jsonを使用します。try節でエラーが発生した場合はdispatchExceptionメソッドを実行します。
Content-typeヘッダーが「text/javascript」から始まる場合(大小文字不問)、前述evalResponseメソッドを使用して受信したデータをevalで処理します。ただし、返却値は取得していません。
以降は通信完了でなくても実行されます。まずoptionsプロパティのオブジェクトにに"on"+(変数eventの値)に該当するメソッドがあれば実行し、なければ何もしません。次にAjax.Responders.dispatchメソッドにより、Ajax.Respondersに登録されたオブジェクトの"on"+(変数eventの値)に該当するメソッドをすべて実行します。つまり、インスタンス個別処理の後に、Ajax関連クラス共通処理を行います。ここも、try節でエラーが発生した場合はdispatchExceptionメソッドを呼び出しています。
最後に、IEでのメモリーリークを回避するためのコードが書かれています。変数eventが"Complete"であればXMLHttpRequestのonreadystatechangeプロパティにPrototype.emptyFunction(無処理関数)を設定しています。申し訳ありませんが、力不足で詳しいことは分かりません。以下は推測です。前述requestメソッドでは以下のようになっています。
【参考】 this.transport.onreadystatechange = this.onStateChange.bind(this);
Functionクラスの拡張メソッドbindを使用して登録しています。ここでのthisへの参照が、通信完了後も自オブジェクトを存続させている、つまり、ガベージコレクトの対象外にしているのではないかと。(ただ、だとすると、IEだけの現象というのも変な気がするのですが・・・。)
参考となると思われるのは以下です。
【参考サイト】 MSDN:Understanding and Solving Internet Explorer Leak Patterns(英語)
上記ページで関連すると思われるのは、2.のClosuresに関する部分ではないかと思います。
dispatchExceptionメソッド
【抜粋】 dispatchException: function(exception) { (this.options.onException || Prototype.emptyFunction)(this, exception); Ajax.Responders.dispatch('onException', this, exception); }
前述メソッドでエラー発生時に呼び出されるメソッド。引数exceptionはエラーオブジェクトです。optionsプロパティのオブジェクトのonExceptionメソッドと、Ajax.Respondersに登録されているオブジェクトのonExceptionメソッドをすべて呼び出します。その際の引数は自オブジェクトとエラーオブジェクトになります。
*1:ただし、素直には動いてくれない気がします。前述evalJSONメソッドを参照してください