Link to home
Start Free TrialLog in
Avatar of DoppyNL
DoppyNL

asked on

GetXMLHttpObject fetch of file *sometimes* fails.

I've got an webapplication that uses javascript to fetch files before they are needed.
But there is some strange bug in the script and I can't seem to find out what the problem is.

      ListHandle = GetXMLHttpObject();
      ListHandle.onreadystatechange = ListStatechange;
      ListHandle.open("GET", List[Position], true);
      ListHandle.send(null);

On the last line of this piece of code *sometimes* this error will occur:

"Illegal procedure call or argument"

I haven't got a clue on why this happens.

Some additional information:
- The script will load up to 200 files this way (loop with a timeout); with a pause of 0,5 seconds between requests.
- The page will be displayed for quite a long time and the loading of the files may be repeated after some time. (so it could be a problem of some sort of timeout).
Avatar of Zvonko
Zvonko
Flag of North Macedonia image

Do it like this:

      List[Position] = {file: List[Position], xhttp: GetXMLHttpObject()};
      List[Position].xhttp.onreadystatechange = new Function("ListStatechange("+Position")");
      List[Position].xhttp.open("GET", List[Position].file, true);
      List[Position].xhttp.send(null);


And change your function ListStatechange(thePos) to take the position number from the List Array to be able to handle the correct xhttp property.

Show the actual version of your ListStatechange() function and I can change it for you.



Avatar of DoppyNL
DoppyNL

ASKER

I only posted a fraction of the code, thinking the rest wouldn't be relevant (as nothing big happens there).

The full code is:

      function ListFile()
      {
            ListFileHandle = GetXMLHttpObject();
            ListFileHandle.onreadystatechange = ListFileStatechange;
            ListFileHandle.open("GET", List[Position], true);
            ListFileHandle.send(null);
      }
      
      function ListFileStatechange()
      {
            if ((ListFileHandle.readyState == 4) || (ListFileHandle.readyState == "complete"))
            {
                  Position += 1;
                  if (Position < List.length)
                  {
                        setTimeout('ListFile();', 500);
                  }
                  else
                  {
                        ListDone();
                  }
            }
      }
      
      function ListDone()
      {
            List = Array();
            Position = 0;
      }


note: even to this code some changes are made. But only in naming conventions and removal of some code that definitly isn't relevant.
ASKER CERTIFIED SOLUTION
Avatar of Zvonko
Zvonko
Flag of North Macedonia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Oh, and when your problem is that the browser is blocked while the file downloads run, then call ONLY the function once by setTimeout.
Like this:

function backGround(){
  setTimeout("ListFile()", 1);
}

Then your ListFile() function will run in the background.

Here another syntax for the background function:

function backGround(){
  setTimeout(ListFile, 1);
}


Avatar of DoppyNL

ASKER

Just to make sure I understand what is happening. Some questions:

- Is it a problem if 2 processes on the same page try to fetch data from the (same) server this way?
   What would be the symptoms of this problem? a fatal error as I mentioned above or would the request be delayed? Would it be a good idea to prevent seperate processes to fetch files at the same time?


There may be several requests done to the server using similar methods, all using GetXMLHttpObject();


When I use your function, wich runs all requests without a delay, wil it download each file one at a time before continuing to the next? Will this prevent problems when another process also wants to request a file from the server?


I'm going to implement the changed code now and see what the results are.
Problem is that it is a little hard to test, as the problem doesn't occur allways :|

You can get hundreds of request on the same page, but you cannot have two requests using the same Object:
ListFileHandle = GetXMLHttpObject();

By assigning the second time GetXMLHttpObject() to ListFileHandle Object you destroy the previous Object with the same name and the running process in the background is disturbed because he tries to update its state there.

Avatar of DoppyNL

ASKER

Sounds very logical, and it is.

Seems that it would be a good idea for me to make sure no requests are made with the same object.
I will write some extra code that will check if the code is allready running for that.


One thing I don't completely understand at the moment.
In your code you have removed the "onreadystate"-function, with that the check for the response-code is removed.

What would happen if the request fails completely? (timeout?)
What would happen if the request fails on the server? (404 or 500?)


allthough I could also write my code so that it still uses the seperate function to process what is returned and on top of that add some code that would prevent it running more than once at the same time.
What will happen? The same thing as in your version: Nothing.
Your version counts the good arrivals and ignores the return codes other then "complete".
My version does exactly the same, it steps to next file transfer ignoring the failed ones.

Ane if you set the third paremeter of open() method to false then you cannot and need not to set the call back function for asynch ready state method.

Avatar of DoppyNL

ASKER

Background:
I use the object to do 2 things:
1 - fetch files from the server so they are in the browser cache before I actually need them (speed things up).
2 - fetch data from the server and do things based on the content.


For the first it is only needed to fetch all files, it doesn't matter what the result of the request is.

For the second I need to make sure that the request was succesfull before I proceed with processing the data.


is it possible to check the response code when not using the ready-state-method?
does the object have an internal timeout mechanism for when the request fails or takes to long? (wich results in a failure of fetching the file)

ie: does this work the same as when I use the ready-state-method?

      Handle = GetXMLHttpObject();
      Handle.open("POST", URI, false);
      Handle.send(null);
      if ((Handle.readyState == 4) || (Handle.readyState == "complete"))
      {
            if (Handle.status == 200)
            {
                  Response = Handle.responseText;
            }
      }



PS: points increased because I'm fishing for information on how the object actually works and because I'm probably very annoying ;-)
Avatar of DoppyNL

ASKER

Is there some kind of `manual` somewhere where all this can be found in detail?
I've been searching for it, but I can only find site's that explain on how you can use it. Not an actual manual that explains the various methods etc.

it would make more sense for me to read the actual manual than to keep bugging people for the answer :P
Here an example: http://www.w3schools.com/ajax/ajax_xmlhttprequest.asp
But when you look closer you will see that there is NO diference betwean asynch and synch method.
You do check the state as deposited in the Handle, so it does not matter wheter the checking script is called separately or inline step by step.
And you are right, the big difference is the Timeout for no response. But that situation you cannot circumvent. You have to react to that in synch and asynch method. What return code you do get for timed out request I do not know exactly, but look here fore more description:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
http://www.answers.com/topic/http-return-codes

Avatar of DoppyNL

ASKER

I've been testing stuff out, a lot...

`strange` thing happening:

When I walk through the list of files and request them using the above method without the ready-state-method, it seems to lock other scripting on the page. (there may be quite some files that need to be downloaded).
The loading of the list is started at the same time as some other processes. The list is loading, but the other processes don't seem to do anything, but they catch up the moment the loading of the list is done.
All processes are started with a setTimeout('TheFunction();', 50); command.
When I change the cache timeout to 500 the problem seems to have disappeared.

I'm probably going back to the ready-state-method for the cache-list. But all other processes (wich only do 1 file) I will keep on the method without the ready-state.


This will ofcourse require some further testing on my side :P
Final decision on this will be made tomorrow morning, as then the updated code will be rolled out into production.


note:
This does work:

      Handle = GetXMLHttpObject();
      Handle.open("POST", URI, false);
      Handle.send(null);
      if (Handle.status == 200)
      {
           Response = Handle.responseText;
      }

The file is requested, when everything is OK, and the request returns 200 you can do what you want.
Funny thing is though, when you do a "alert(Handle.status);" it will alert 200.
But when the server returns a 404, it will not alert 404.
But I don't really care, as I only need to do something when it was succesfull.


I will get back to this tomorrow.
You can get also files one by one in synch mode to avoid lock out of concurent scripting.
Like this:

var nextFile = 0;  //force var global
function ListFile(){
   var ListFileHandle = GetXMLHttpObject(); // keep var local
   if(nextFile<List.length){
      ListFileHandle.open("GET", List[nextFile], false);
      ListFileHandle.send(null);
      if (Handle.status == 200){
           Response = Handle.responseText;
      }
      nextFile++;
      setTimeout(ListFile, 50);
    } else {
      alert("All "+List.length+" files downloaded.");
    }
}



Avatar of DoppyNL

ASKER

New method seems to be working.

I have however encountered a problem that may be related to fetching the files.

The process needs to be run repeatedly, with pauzes in between.
I've written some code to prevent the process to be started a second time when the first is not done yet.

This code now causes the process not to be called again in SOME CASES.
My guess is that the request is failing some way and the rest of the function is not run properly OR that the request doesn't timeout and keeps on waiting for something that will not happen anymore.

I'm planning on using the ready-state function again and adding some timeout functionality.
When it takes to long, the process will timeout.

I believe there is a "abort" method that will allow me to abort the request and continue normally.

Does an errormessage by Internet Explorer 6 about "offline files" telling me there is no internet connection and asking me if I want to work offline ring a bell in combination with this type of coding?
We had this problem, but making sure a proces isn't run twice seemed to have solved this, but I'm not sure yet.

I am not sure but I think there is NO script method to see wether you have network connection or not.
All you can do is to observe the request timing and do on your own request aborts before the long default timeout set by OS registry will return a failed status code.

Avatar of DoppyNL

ASKER

Answer accepted that is most relevant to the whole question.
Allthough other replys were also very usefull.

I now have a good understanding on how the fetching of the files within javascript works and I will be able to fix this myself further.
There are some other factors I need to keep into account when changing the code in question, and I've got some other priorities that need to be done first now.
Leaving this question open until completely resolved on my side would simply take to long.

Thanx for the help!
You are welcome.