An approach to an AJAX class

B

bizt

Hi,

I have an AJAX class that is designed to be instantiated many times
where ever it may be used. For example, if I have a function, when I
call that function an instance of the AJAX class is created (and
hopefully destroyed at the end). See:

function makePricesCall() {
var ajax = new AjaxClass;
ajax.url = "getPrices.php";
ajax.onSuccess = function {...};
ajax.send();
}

The function instantiates the class, sets the url and handler function
(onSuccess) then makes the call (send). Now, what I do like about this
is that I can make simultaneous calls from different instances of the
same class. For example, in my app I have two calls which combined
build a single page. The first call is to get the market info and is
typically called once. The second call is to get the prices of that
market (which change frequently) and this is called every 20 seconds
to keep these up to date. The first time the page is rendered it makes
a call to both at the same time, the function that builds the page
waits til both data feeds have been received. This is faster than
calling one then calling the other and to my knowledge the only way I
can do this is by having two instances of my class (which internally
have their own unique instance of XHR). Even on each refresh of the
prices though a new class instance is created

What I am worried about is that over time because Im always
instantiating new objects that these will take up memory, even the old
objects no longer in use. Should I perhaps have a unique instance of
the AJAX class for each data feed, this way I can make simultaneous
calls to two different feeds (market and price) but when I need to
make a second call to the prices it uses the same AJAX object as
before and doesn't have to create a new one. This way I could
incorporate some queuing also. Ive always gone on the assumption
however that when a variable (in this case an object of my class) is
created locally to that function it is destroyed when the function
ends but when the function ends it must be kept somewhere as its still
able to call the handler function onSuccess. Is this the case? After a
few hours of the app running are these just going to be taking up more
memory than is really needed?

Anyway would be great to get some feedback on recommend theory when
building such a class, be much appreciated. Im aware there are lots of
ready made AJAX wrapper classes out there but I prefer to build my own
so I can add my own things to them when they are needed (eg. ajax
caching)

Cheers
Burnsy
 
B

bizt

By the way, here is my Ajax class (AjaxWrapper). Would also really
appreciate some feedback on how susceptible it is to memory leaks

function AjaxWrapper() {

// PROPERTIES

this.method = "GET";
this.url = "";
this.responseText = null;
this.responseXML = null;

var _obj = this; // reference to object
var _sStatusText; // when the call is done this is set, used in event
of error notification

// METHODS

this.onSuccess = function() {
// this is the function that will handle the response. It is
intended to be
// defined after instantiation. It cannot be passed any params but
instead
// use this.variables array to pass params when setting object up


};

this.onFail = function() {
// this is the function that will handle the response where it has
failed


};

this.send = function() {
// get data from the server and handle response

this.method = "GET";
_send(null);
};

function _send(sData) {
// get data from the server.
// - sData: only requried for posts

var oXmlhttp = null;

//
if (window.XMLHttpRequest) {// code for IE7, Firefox, Mozilla, etc.
oXmlhttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {// code for IE5, IE6
oXmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
if (oXmlhttp==null) {
alert("Your browser does not support XMLHTTP.");
}

// create url with time stamp //
var tmpUrl = _obj.url;
if(tmpUrl.indexOf("?") >= 0) {
tmpUrl = tmpUrl.replace("?", "?t="+(new Date()).getTime()+"&"); //
sneak a timestamp inbetween ? and name/value pairs
} else {
tmpUrl = tmpUrl + "?t="+(new Date()).getTime();
}

oXmlhttp.open(_obj.method, tmpUrl, true);

oXmlhttp.onreadystatechange = function() {
if (oXmlhttp.readyState==4) { // 4 = "loaded"

// set status text
_sStatusText = oXmlhttp.statusText;

if (oXmlhttp.status==200) { // 200 = "OK"

// update vars
_obj.responseText = oXmlhttp.responseText;
_obj.responseXML = oXmlhttp.responseXML;

// call handler
_obj.onSuccess();

} else {

// call handler
_obj.onFail();

}
}
};

// send the data with the XHR->send() method
oXmlhttp.send(sData);

}

}



... as mentioned above, this is generally how I might use it:

function getMarket() {
var ajax = new AjaxWrapper;
ajax.url = "data/marketData.php";
ajax.onSuccess = function {...};
ajax.send();
}

function getPrices() {
var ajax = new AjaxWrapper;
ajax.url = "data/marketData.php";
ajax.onSuccess = function {...};
ajax.send();
}

..
..
..

// SCRIPT //

getMarket();
getPrices();



... notice how both functions are called in the same go (one right
after the other) so reallytwo simultaneous calls are on the go at
once. The only way I know to do this is to have two instances of XHR
object contained within each of my obects from the two functions. Now,
when the two function calls are done and the onSuccess handlers are
finished I want to the memory taken up for these objects to be wiped.
When I need to update prices, in say 20 seconds, I will create a new
local AjaxWrapper object local to that function. This is the part Im
wondering if left for a few hours, will this be needlessly filling up
memory. Am I managing this well with the method Ive adopted or should
I be doing things differently?

Cheers (again)
Burnsy
 
T

Thomas 'PointedEars' Lahn

bizt said:
I have an AJAX class

No, you do not. You are using a OOPL that uses prototype-based inheritance.
So instead you have created a constructor for a user-defined object, a
Function object that can be referred to by `AjaxClass' at least.
that is designed to be instantiated many times
where ever it may be used. For example, if I have a function, when I
call that function an instance of the AJAX class is created (and

No, it can only be said that an `AjaxClass' instance is created; that is, an
Object instance (or short and perhaps less confusing: an object) that has
the object referred to by `AjaxClass.prototype' in its prototype chain.
hopefully destroyed at the end).

When the object is no longer referred to, it is marked for garbage
collection. If and when it is "destroyed" (i.e. when the memory allocated
for storing its properties is freed), depends on the used garbage collector
which is at the discretion of the ECMAScript implementation (and maybe even
the user).
See:

function makePricesCall() {
var ajax = new AjaxClass;
ajax.url = "getPrices.php";
ajax.onSuccess = function {...};
ajax.send();
}

The function instantiates the class

It does not, see above.
sets the url and handler function
(onSuccess) then makes the call (send). Now, what I do like about this
is that I can make simultaneous calls from different instances of the
same class.

No, reasonably you cannot because although you create an object that
implements the IXMLHTTPRequest interface only when you call the send()
method of your object (which allows virtually simultaneous request-response
handling within the connection constraints imposed by the HTTP client),
there is a race condition when you modify the `method' and `url' properties.
In addition, there is a race condition when accessing the `responseText' and
`responseXML' properties of your object.
What I am worried about is that over time because Im always
instantiating new objects that these will take up memory, even the old
objects no longer in use.

Reducing closures and avoiding circular references is a first step in
avoiding the problem. Read the FAQ.
Should I perhaps have a unique instance of
the AJAX class for each data feed, this way I can make simultaneous
calls to two different feeds (market and price) but when I need to
make a second call to the prices it uses the same AJAX object as
before and doesn't have to create a new one.

Exactly (except for the repeated misuse of the term "call" in your posting).
However, you will also need to make sure that the second request to the
prices resource does not occur before the previous response has been fully
received and processed, or you need to check the status of the previous
request-response handling and create a new IXMLHTTPRequest object when
necessary.
When I need to update prices, in say 20 seconds, I will create a new
local AjaxWrapper object local to that function. This is the part Im
wondering if left for a few hours, will this be needlessly filling up
memory. Am I managing this well with the method Ive adopted or should
I be doing things differently?

As you cannot know when garbage collection takes place, you should reuse
objects as much as possible.

Your object should have a property, or send() should have a return value,
indicating when XHR is not supported so that fallbacks can take over. Also,
you should implement support for POST requests. And the Date part is
unnecessary and potentially harmful (it cures the symptoms instead).


PointedEars
 
V

VK

bizt said:
I am aware there are lots of
ready made AJAX wrapper classes out there but I prefer to build my own
so I can add my own things to them when they are needed

I think that everyone can fully understand that: but ever since Feb.
2005, when James Garrett from the Adaptive Path started this bizz,
c.l.j. (aka comp.lang.javascript) got over 6,500 Ajax (AJAX, XHR)
related posts with over 300 of them stating that "I know that everyone
does it, but I want to do yet another one by myself".
In the run of 2005 the old hobby of custom cross-browser multilevel*
drop-down+ menus got completely replaced by custom cross-browser
XHR'ing and still in a big fashion.

It doesn't mean at all that XHR-related post are not welcome, I just
see that you put some good efforts in making long descriptive posts
and so wanted to warn you if you not get the expected feedback.

XHR by itself is a relatively simple and standard routine but on the
deployment stage browser-specific peculiarities are coming into game:
and it may get boring to answer "why is so in browser X", "why that on
browser Y" etc. I am daring to suggest to take a look at AjaxRequest
by Matt Kruse
http://www.ajaxtoolbox.com/request/source.php
to see what particular coding for what particular reasons had to be
involved.


P.S. Also introducing Thomas 'PointedEars' Lahn of c.l.j. :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top