Solved

GetXMLHttpObject fetch of file *sometimes* fails.

Posted on 2007-03-21
17
650 Views
Last Modified: 2008-01-09
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).
0
Comment
Question by:DoppyNL
  • 9
  • 8
17 Comments
 
LVL 63

Expert Comment

by:Zvonko
Comment Utility
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.



0
 
LVL 6

Author Comment

by:DoppyNL
Comment Utility
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.
0
 
LVL 63

Accepted Solution

by:
Zvonko earned 500 total points
Comment Utility
Relevant is that the third paremeter is set to: TRUE
ListFileHandle.open("GET", List[Position], true);

Therefore you have NO control when the Asynchronouse callback function is called.
Sometimes happens that you use one copy of the ListFileHandle object while another asynchrounous call tries to use it too. And then you get your problem.

You have delay in your callback function so better would be this loop (it will be without delay):

function ListFile(){
   ListFileHandle = GetXMLHttpObject();
   for(var Position=0;Position<List.length;Position++){
      ListFileHandle.open("GET", List[Position], false);
      ListFileHandle.send(null);
    }
    alert("All "+List.length+" files downloaded.");
}




0
 
LVL 63

Expert Comment

by:Zvonko
Comment Utility
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);
}


0
 
LVL 6

Author Comment

by:DoppyNL
Comment Utility
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 :|

0
 
LVL 63

Expert Comment

by:Zvonko
Comment Utility
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.

0
 
LVL 6

Author Comment

by:DoppyNL
Comment Utility
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.
0
 
LVL 63

Expert Comment

by:Zvonko
Comment Utility
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.

0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 6

Author Comment

by:DoppyNL
Comment Utility
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 ;-)
0
 
LVL 6

Author Comment

by:DoppyNL
Comment Utility
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
0
 
LVL 63

Expert Comment

by:Zvonko
Comment Utility
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

0
 
LVL 6

Author Comment

by:DoppyNL
Comment Utility
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.
0
 
LVL 63

Expert Comment

by:Zvonko
Comment Utility
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.");
    }
}



0
 
LVL 6

Author Comment

by:DoppyNL
Comment Utility
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.

0
 
LVL 63

Expert Comment

by:Zvonko
Comment Utility
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.

0
 
LVL 6

Author Comment

by:DoppyNL
Comment Utility
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!
0
 
LVL 63

Expert Comment

by:Zvonko
Comment Utility
You are welcome.
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Article by: DanRollins
This article describes a JavaScript program that creates a maze made of hexagonal cells.  In Part 2 (http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/A_7850-Hex-Maze-Part-2.html), we'll extend the program by adding a depth-…
This article demonstrates how to create a simple responsive confirmation dialog with Ok and Cancel buttons using HTML, CSS, jQuery and Promises
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now