1

I am giving my first steps in Javascript and trying to understand how it works. I've come to a problem of execution order of the code.

var Parsed = [[]]
var txtFile = new XMLHttpRequest();
alert("Trying to open file!");

txtFile.open("GET", "http://foo/f2/statistics/nServsDistrito.txt", false);
txtFile.onreadystatechange = function() {
if (txtFile.readyState === 4) {  // Makes sure the document is ready to parse.
    if (txtFile.status === 200) {  // Makes sure it's found the file.
         alert("File Open");
         allText = txtFile.responseText; 
         Parsed = CSVToArray(allText, ",")
         }
    }
}
txtFile.send(null); 

alert("Job Done");

The problem is "Job Done" is appearing first than "File Open".

But the file has information necessary for code following the "Job Done" alert. I changed the asynchronous part of the "get" request but didn't work.

What can i do to stand by all code while the file is open and the information retrieved? Can i use the readyState to stall the code while the file is being opened and parsed?

Thanks for the help.

Update: It now works thanks to all.

M1nga
  • 53
  • 7
  • 1
    XMLHttpRequest is **asynchronous**, open will be executed in parallel with your function (and onreadystatechanged will be executed when your function finished its job to keep your code "single threaded"). – Adriano Repetti May 02 '13 at 09:09
  • 1
    Move the last 3 `}` to the very bottom. – Moritz Roessler May 02 '13 at 09:12
  • What is the use of an event handler if the request is synchronous? Move the code inside event handler between `.send` and `alert(done)` – Salman A May 02 '13 at 09:14
  • 1
    Have a look at the first part of [my answer here](http://stackoverflow.com/a/14220323/218196). It tries to explain the difference between synchronous and asynchronous code. – Felix Kling May 02 '13 at 09:21
  • 1
    try to replace the 'false' with 'true' in the txtFile.open() method then run it. you will feel the difference . please try to do like that as above people said but its not a good practice to make synchronous calls – radha krishna May 02 '13 at 09:22

2 Answers2

0

That's because you are using asynchronous functions. When working with async functions you have to use callbacks.
A callback is a function (eg. function cback()) you pass as parameter to another function (eg function async()). Well, cback will be used by async when necessary.
For example, if you are doing IO operations like reading files or executing SQL queries, the callback can be used to handle the data once retrieved:

asyncOperation("SELECT * FROM stackoverflow.unicorns", function(unicorns) {
    for(var i=0; i<unicorns.length; i++) {
        alert("Unicorn! "+unicorns[i].name);
    }
});

The anonymous function we are giving asyncOperation as the second parameter is the "callback", and it's going to be executed once the query data is ready. But while that operation is being handled your script is not blocked, this means that if we add this line after the previous code:

alert("We are not blocked muahahaha");

That alert will be shown before the query is completed and unicorns appear.

So, if you want to do something after the async task finishes, add that code inside the callback:

asyncOperation("SELECT * FROM stackoverflow.unicorns", function(unicorns) {
    for(var i=0; i<unicorns.length; i++) {
        alert("Unicorn! "+unicorns[i].name);
    }
    //add here your code, so that it's not executed until the query is ready
});

Note: as @radhakrishna pointed in a comment the open() function can also work in a synchronous manner if you pass true instead of false. This way the code will work as you were expecting: line after line, in other words: synchronously.


Callbacks can be used for a lot of things, for example:

function handleData(unicorns) {
    //handle data... check if unicorns are purple
}
function queryError(error) {
    alert("Error: "+error);
}
asyncOperation("SELECT * FROM stackoverflow.unicorns", handleData, queryError);

Here we are using two callbacks, one for handling the data and another one if an error occurs (of course that depends on how asyncOperation works, each async task has it's own callbacks).

Salvatorelab
  • 11,614
  • 6
  • 53
  • 80
  • Thanks for the response and the explanation! :) – M1nga May 02 '13 at 10:44
  • You are welcome. Once you understand how sync/async works have a look at this: https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Synchronous_and_Asynchronous_Requests there are some helpful examples – Salvatorelab May 02 '13 at 10:46
0

XMLHttpRequest is an async operation. It doesn't matter whether your file is readily available or even if there is no networking involved. Because it is an async operation, it will always execute after after any sequential/synchronous code. That's why you have to declare a callback function (onreadystatechange) that will be called when open comes back with the file contents.

By the explanation above, your code in this example wouldn't be correct. The alert line will be executed immediately, not waiting for the file contents to be ready. The job will only be done when onreadystatechange has finished executing, so you would have to put the alert at the end of onreadystatechange.

Another very common way to trigger async operations is by using setTimeout, which forces its callback function to be executed asynchronously. Check out how it works here.

Edit: You are indeed forcing the request to be synchronous by setting the third parameter to open to false (https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#open()). There are very few cases in which you want a request like that to be synchronous, though. Consider whether you need it to be synchronous, because you will be blocking your whole application or website until the file has been read.

Sergi Mansilla
  • 12,495
  • 10
  • 39
  • 48
  • 1
    XMLHttpRequest is not necessarily asynchronous. The third parameter in `.open` can be set to false to make it synchronous. – Salman A May 02 '13 at 09:45