another way to prevent memory leak in IE when using XMLHTTPRequest
This post is a follow up of my former leak-free XMLHttpRequest Wrapper post. So if you have not gone through it, read it to get an initial idea.
By the way, I'm improving XHRequest of sardalya (and many other objects), a brand new release will come before this weekend.
Anyway, I was seriously thinking that somehting was wrong about the XHRequest._cleanup method:
So each time I use a new get request, I was re-creating a new XMLHttpRequest member for (this._xhr), since I was setting the object to null in the last line.
Removing the last line would theoretically be sufficient. But I was secretly wanting to set this._xhr.onreadystatechange=null;
I'll come to this point later. But just before that let me introduce a small test script explaining closures and scopes:
When you run the script on body load, TestObject.initialize() method is called for the first time. So when you click on TestLayer it will alert [Object] and then assings a new function to the onclick. Therefore when you click TestLayer for the second time it will alert undefined.
Do you see where I am getting?
Just one line of code!
This syntax completely removes the closure, whereas it does not destroy this._xhr, so you do not have the memory overhead of recrating a new XMLHttpRequest object (since this._xhr is not set to null, we just need re-assign this._xhr.onreadystatechange).
It is better than the first one. It is also cooler, I guess ;)
Describing it with a code sample would be more clear I guess:
In the former version of the script, we were always creating a new XMLHttpRequest object because we were assigning this._xhr=null; after each cleanup. Now, we do not set it to null. So the code-flow will enter the highlihted part only once (in object's creation). Only the first line will execute thereafter, which is better in terms of performance (creating a new XMLHttpRequest at each HTTP GET request to server will be a costly operation, especially if you are creating and AJAX-heavy application and you are using many many of those objects around).
NILL is an object
Secondly, this approach makes NULL an object!. I mean NULL is now an object, just as nill is an object in Ruby.
Most of you have seen "null is null or not an object" error message at least once in your life time ;)
null is not an object but NULL is. So we may even extend it a bit:
I'm just thinking aloud though.
But I'm sure ruby guys (and gals) around will like this approach.
Cheers.
bu yaziyi sevdin mi?
hemen
una ekle!
By the way, I'm improving XHRequest of sardalya (and many other objects), a brand new release will come before this weekend.
Anyway, I was seriously thinking that somehting was wrong about the XHRequest._cleanup method:
_this._cleanup=function()
{
if(!this._xhr)return;
delete this._xhr.onreadystatechange;
this._xhr=null;
};
So each time I use a new get request, I was re-creating a new XMLHttpRequest member for (this._xhr), since I was setting the object to null in the last line.
Removing the last line would theoretically be sufficient. But I was secretly wanting to set this._xhr.onreadystatechange=null;
which I could not. Since IE was generating a type mistmatch error if I try.
_this._cleanup=function()
{
/*if you try to set the event handler to null to break the circular reference.
This will not work in IE, and it will throw a type mistmatch exception.*/
this._xhr.onreadystatechange=null;
};
I'll come to this point later. But just before that let me introduce a small test script explaining closures and scopes:
/body\
/script\
var Constant={
NULL:function()
{
/*
* This method does not close over testMember.
* testMember is out of scope.
* This will just alert "undefined".
*/
alert(typeof testMember);
}
}
var TestObject=function()
{
this.initialize();
};
TestObject.prototype.initialize=function()
{
var testMember=document.getElementById("TestLayer");
var self=this;
if(arguments.length)
{
testMember.onclick=Constant.NULL;
}
else
{
testMember.onclick=function()
{
/*
* Here, this anonymous function closes over testMember;
* testMember is within the scope of it.
* this will alert [Object].
*/
alert(typeof testMember);
self.initialize(true);
};
}
};
window.onload=function(evt)
{
var to=new TestObject();
};
//script\
/div id="TestLayer"\Test Layer//div\
//body\
When you run the script on body load, TestObject.initialize() method is called for the first time. So when you click on TestLayer it will alert [Object] and then assings a new function to the onclick. Therefore when you click TestLayer for the second time it will alert undefined.
Do you see where I am getting?
var Constant=
{
...,
NULL:function{}
};
...
_this._cleanup=function()
{
this._xhr.onreadystatechange=Constant.NULL;
};
Just one line of code!
This syntax completely removes the closure, whereas it does not destroy this._xhr, so you do not have the memory overhead of recrating a new XMLHttpRequest object (since this._xhr is not set to null, we just need re-assign this._xhr.onreadystatechange).
It is better than the first one. It is also cooler, I guess ;)
Describing it with a code sample would be more clear I guess:
...
_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;
};
In the former version of the script, we were always creating a new XMLHttpRequest object because we were assigning this._xhr=null; after each cleanup. Now, we do not set it to null. So the code-flow will enter the highlihted part only once (in object's creation). Only the first line will execute thereafter, which is better in terms of performance (creating a new XMLHttpRequest at each HTTP GET request to server will be a costly operation, especially if you are creating and AJAX-heavy application and you are using many many of those objects around).
NILL is an object
Secondly, this approach makes NULL an object!. I mean NULL is now an object, just as nill is an object in Ruby.
Most of you have seen "null is null or not an object" error message at least once in your life time ;)
null is not an object but NULL is. So we may even extend it a bit:
Well it makes things overcomplicated I know (why not use myvar===null instead of Constant.NULL.equals(myVar) -- it's impractical).
Constant.NULL._isNull=true;
Constant.NULL.prototype.toString=function(){return "NULL"};
Constant.NULL.prototype.equals=function(someObject)
{
//return someObject===null||(someObject&&someObject._isNull);
return (someObject&&someObject._isNull);
}
I'm just thinking aloud though.
But I'm sure ruby guys (and gals) around will like this approach.
Cheers.
bu yaziyi sevdin mi?
hemen
una ekle!
- permalink: 6:32 AM


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