Handle OnReadyStateChange with array of XMLHTTP objects

K

Krzysztof Kubiak

I'm trying to make use of XMLHTTP object, but I've come across a
problem.
It seems that there is no way to create dynamic array of such XMLHTTP
objects (to make several requests) and handle them properly.
I was trying to use such code:

<script lang="javascript">

function handleOnReadyStateChange() {
if (this.readyState==4) {
//some actions
}
}

function createObjArray() {
var XmlHttp = new Array();

for (var i = 1; i<=10; i++) {
XmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
XmlHttp.open("GET", url, true);
XmlHttp.onreadystatechange = handleOnReadyStateChange;
}
}

createObjArray();
</script>

Unfortunately when event handler function is accessed, 'this' isn't
set to an object which fired event.

I was doing literally EVERYTHING (or at least I think so) to make it
work but ... with no success.

Behavior of this handler is somehow different from what I was used to,
because I could with no problem do similiar task with Image object.

<script lang="javascript">

function handleImgOnLoad() {
document.getElementById(this.name).src = this.src;
document.getElementById(this.name).width = Math.round(this.width/4);
document.getElementById(this.name).height =
Math.round(this.height/4);
}

function createImageArray {
var images = new Array();

for(i=1;i<=10;i++) {
images = new Image();
images.src = 'some_url';
images.name = i;
images.onload = handleImgOnLoad;
}
}

createImageArray();
</script>

So my guess is that problem lies in XMLHTTP object which doesn't set
reference to itself in its event handler.

Does anyone knows if it is possible to do what I'm trying to do ?
I would really appreciate any help.
 
L

Lasse Reichstein Nielsen

I'm trying to make use of XMLHTTP object, but I've come across a
problem.
It seems that there is no way to create dynamic array of such XMLHTTP
objects (to make several requests) and handle them properly.
I was trying to use such code:

<script lang="javascript">

function handleOnReadyStateChange() {

Here "this" does refer to an instance of ActiveXObject, as can be seen
by adding:
alert([this,this instanceof ActiveXObject,this.readyState]);
So the "this" is set, it's just the readyState that is broken?
Or it is not the actual object, but another instance?
for (var i = 1; i<=10; i++) {
XmlHttp = new ActiveXObject("Msxml2.XMLHTTP");


I noticed that this doesn't create a new object each time, but the
same object several times. You can see this if you add:
if (i>1) {alert([i-1,i,XmlHttp==XmlHttp[i-1]]);}

Behavior of this handler is somehow different from what I was used to,
because I could with no problem do similiar task with Image object.

Well, it's a host object. They can do pretty much anything they want,
and still be in compliance with the ECMAScript standard.
<script lang="javascript">
type="text/javascript"
!

for(i=1;i<=10;i++) {
images = new Image();
images.src = 'some_url';
images.name = i;
images.onload = handleImgOnLoad;


I suggest adding the onload hander before setting the src property.
That way an already cached image can't be considered loaded *before*
the handler is set.
So my guess is that problem lies in XMLHTTP object which doesn't set
reference to itself in its event handler.

It sets something that is an instance of ActiveXObject. And the same
object every time (at least according to ==).
Does anyone knows if it is possible to do what I'm trying to do ?
I would really appreciate any help.

Can't help you, sorry. Just noticing some more odd behavior.

/L
 
L

Lasse Reichstein Nielsen

Lasse Reichstein Nielsen said:
Here "this" does refer to an instance of ActiveXObject, as can be seen
by adding:
alert([this,this instanceof ActiveXObject,this.readyState]);

Another wonder was that I added:

var n;
for(var i=1;i<XmlHttp.length;i++) { // I made XmlHttp global for this
if (this == XmlHttp) {n=i;break;}
}
alert([this,n]);

The wonder is that they all compare equal to XmlHttp[1]. However, if
I change == to ===, this is not equal to any of the XmlHttp elements.
I noticed that this doesn't create a new object each time, but the
same object several times. You can see this if you add:
if (i>1) {alert([i-1,i,XmlHttp==XmlHttp[i-1]]);}


But now I can't reproduce that. Probably me seeing spooks.


Anyway, a solution is to not use the same handleOnReadyStateChange
function for all the requests, but create a new one for each request
that knows what object it belongs to:

function makeHandleOnReadyStateChange(XmlHttp) {
return function() {
if (XmlHttp.readyState == 4) {
alert(self.responsText); // or something
}
}
}

and then in the loop:

XmlHttp.onreadystatechange = makeHandleOnReadyStateChange(XmlHttp);

It seems to work.
/L
 
M

Martin Honnen

Lasse said:
I'm trying to make use of XMLHTTP object, but I've come across a
problem.
It seems that there is no way to create dynamic array of such XMLHTTP
objects (to make several requests) and handle them properly.
I was trying to use such code:

<script lang="javascript">

function handleOnReadyStateChange() {


Here "this" does refer to an instance of ActiveXObject, as can be seen
by adding:
alert([this,this instanceof ActiveXObject,this.readyState]);
So the "this" is set, it's just the readyState that is broken?
Or it is not the actual object, but another instance?

It is the window object, try
window === this
inside the event handler. And yes
window instanceof ActiveXObject
is true, any host object in IE/Win will probably yield true of
instanceof ActiveXObject.

The problem is with the onreadystatechange event handler not being set
up to have this point to the object the handler is attached to (and
firing on).
With IE this remains the window (global) object but with
Mozilla/Netscape it is not better as there this in the
onreadystatechange handler is the function itself.
And the usual way with evt.target respectively window.event.srcElement
doesn't work either, Mozilla doesn't even set the evt parameter and IE
doesn't set the srcElement.
So indeed the only way for the onreadystatechange handler to reliably
access the object it is firing on is using a closure.
 
K

Krzysztof Kubiak

Anyway, a solution is to not use the same handleOnReadyStateChange
function for all the requests, but create a new one for each request
that knows what object it belongs to:

function makeHandleOnReadyStateChange(XmlHttp) {
return function() {
if (XmlHttp.readyState == 4) {
alert(self.responsText); // or something
}
}
}

and then in the loop:

XmlHttp.onreadystatechange = makeHandleOnReadyStateChange(XmlHttp);

It seems to work.
/L


Thanks for pointing me in the right direction. Now I can handle each
object in the proper manner, although I still have a problem which I
will probably not solve until next year ;)

Each of the created event handlers responses independently, but it
seems that I'm not getting proper responses.
The reason why I'm using this loop to create XmlHttp objects is to
find if sequential images exists. I'm iterating through the subsequent
images (http://myserver.net/img001.jpg,
http://myserver.net/img002.jpg, etc.) and if I get XmlHttp.statusText
== 'OK' and XmlHttp.getResponseHeader("Content-Type") == 'image/jpeg'
I'm incrementing counter on the page (inside each of the handlers)
like this:
document.getElementById('counter').innerHTML =
parseInt(document.getElementById('counter').innerHTML) + 1;

Now I only get proper Content-type inside first handler, the other
ones give me Content-Type = 'text/html'.
I was wondering what 'arrives' in these responses and it was some
non-default 404 page, which means that file was not found on the
server (I know it is definitely there).
So ... I guess I know what I'll be dealing with, after New Year's Eve
party.

Once again thanks for your answers
 
M

Martin Honnen

Krzysztof Kubiak wrote:

The reason why I'm using this loop to create XmlHttp objects is to
find if sequential images exists. I'm iterating through the subsequent
images (http://myserver.net/img001.jpg,
http://myserver.net/img002.jpg, etc.)

If you only want to check whether a resource exists on the server then I
strongly suggest not to send a HTTP GET request but only a HTTP HEAD
request e.g. use
XmlHttp.open("HEAD", url, true);
That way the server sends only the HTTP response headers back but not
the complete image.
 
J

Jim Ley

If you only want to check whether a resource exists on the server then I
strongly suggest not to send a HTTP GET request but only a HTTP HEAD
request e.g. use
XmlHttp.open("HEAD", url, true);
That way the server sends only the HTTP response headers back but not
the complete image.


Watch out on many java servers, they often jsut wack out a 500 if you
try a head on them. (not relevant for static images of course, but if
you're checking other pages.)

Jim.
 

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,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top