A simple, leak free, defensive XMLHttpRequest Wrapper
As you may have known Internet Explorer is the king of the leakers.
And XMLHttpRequest (in other words "Microsoft.XMLHTTP" ActiveX component) is not an exception to this.
In this post, I will try to explain where the component may leak and how we can avoid those leaks.
Let us begin with a typical wrapper:
where getObject may be defined as:
The problem is that, we have created a closure in Listing 1:

and closures between DOM world and JS world will cause a memory leak in IE.
To sort out this we will need to implement a few helpers:
First let us alter the onreadystatechange handler a bit:
And the _cleanup method as:
And, for the interested, here follows the entire lightweight
XMLHttp wrapper (which I am currently enhancing a lot and will fully integrate to the next version of sardalya. )
Sorry for the indentation and typos in the code. It is blogger's WYSIWYG mode's fault not mine :)
bu yaziyi sevdin mi?
hemen
una ekle!
And XMLHttpRequest (in other words "Microsoft.XMLHTTP" ActiveX component) is not an exception to this.
In this post, I will try to explain where the component may leak and how we can avoid those leaks.
Let us begin with a typical wrapper:
[LISTING 1]
var _this=XHRequest.prototype;
function XHRequest(){
this.init();
}
_this.init=function(){
var sourceElement=this;
this._xhr=this.getObject();
if(!this._xhr)return;
this._xhr.onreadystatechange=function(){
var obj=sourceElement.getObject();
if(obj.readyState==4){
/*
* 404: file not found.
* 200: OK.
* 304: reading from cache.
*/
if(obj.status==200 OR obj.status==304)
sourceElement.oncomplete(obj.responseText,obj.responseXML);
else
sourceElement.onerror(obj.status,obj.statusText);
}
};
};
where getObject may be defined as:
[LISTING 2]
_this.getObject=function(){
if(this._xhr)return this._xhr;
else if(window.XMLHttpRequest)return new XMLHttpRequest();
else if(window.ActiveXObject)
return new ActiveXObject("Microsoft.XMLHTTP");
else return null;
};
The problem is that, we have created a closure in Listing 1:

and closures between DOM world and JS world will cause a memory leak in IE.
To sort out this we will need to implement a few helpers:
First let us alter the onreadystatechange handler a bit:
... code snippped ...
/*
* 404: file not found.
* 200: OK
* 304: reading from cache.
*/
if(obj.status==200obj.status==304)
sourceElement.oncomplete(obj.responseText,obj.responseXML);
else sourceElement.onerror(obj.status,obj.statusText);
/*to prevent IE memory leak due to circular COM referencing.*/
sourceElement._cleanup();
And the _cleanup method as:
_this._cleanup=function(){
if(!this._xhr)return;
/*
* this._xhr.onreadystatechange = null generates
* a "type mismatch" error in IE.
* So, to release circular reference
* we delete this._xhr.onreadystatechange;
*
* Actually, either setting this._xhr=null
* or "delete"ing this._xhr.onreadystatechange
* is enough to prevent memory leak.
*
* That is, the first line of the code below
* is just added to be on the safe side.
*/
delete this._xhr.onreadystatechange;
this._xhr=null;
};And, for the interested, here follows the entire lightweight
XMLHttp wrapper (which I am currently enhancing a lot and will fully integrate to the next version of sardalya. )
Sorry for the indentation and typos in the code. It is blogger's WYSIWYG mode's fault not mine :)
_this=XHRequest.prototype;
function XHRequest()
{
this.init();
}
_this.init=function()
{
var sourceElement=null;
this._xhr=this.getObject();
if(!this._xhr)return;
sourceElement=this;
this._xhr.onreadystatechange=function()
{
var obj=sourceElement.getObject();
if(obj.readyState==4)
{
if(obj.status==200 OR
obj.status==304)sourceElement.oncomplete(
obj.responseText,obj.responseXML);
else sourceElement.onerror(obj.status,obj.statusText);
sourceElement._cleanup();
}
};
};
_this.getObject=function()
{
if(this._xhr)return this._xhr;
else if(window.XMLHttpRequest)return new XMLHttpRequest();
else if(window.ActiveXObject)return new ActiveXObject("Microsoft.XMLHTTP");
else return null;
};
_this.finalize=function()
{
if(!this._xhr)return;
this._cleanup();
};
_this.get=function(strURL,_blnSync)
{
if(!this._xhr)return null;
if(!_blnSync)_blnSync=false;
this._xhr.open("GET",strURL,!_blnSync);
this._xhr.send(null);
};
_this.getSynchronized=function(strURL)
{
this.get(strURL,true);
};
_this.abort=function()
{
if(this._xhr)this._xhr.abort();
this._cleanup();
};
_this._cleanup=function()
{
if(!this._xhr)return;
delete this._xhr.onreadystatechange;
this._xhr=null;
};
_this.oncomplete=function(strResponseText,objResponseXML)
{
alert("Completed everything.");
};
_this.onerror=function(intStatus,strStatusText)
{
alert("An error occured but my owner is too lazy to handle it.");
};
bu yaziyi sevdin mi?
hemen
una ekle!
- permalink: 11:40 PM


0 Coments
Post a Comment
Links to this post:
Create a Link
<< Home