Based on chrome developer tools a breakpoints I think I'm dealing with a scope issue I can figure out. Is it the way I define the function? The script below is an include js file and the array ' timeStamp I want available for use in other functions without having to call my loadData function everytime.
The timeStamp array goes undefined once it leaves the for loop before it even leaves the function.
var timeStamp = []; // Want this array to be global
function loadData (url){
$.getJSON(url, function(json) {
for (var i=0;i<json.length;i++){
timeStamp.push(json[i].TimeStamp);
}
console.log(inputBITS); //returns the value
});
console.log(inputBITS); //undefined
}
Thank you for anyhelp
It looks like the issue is that getJSON is asynchronous. When it executes and finishes and your code continues on, it indicates only the START of the networking operation to retrieve the data. The actual networking operation does not complete until some time later.
When it does complete, the success handler is called (as specified as the second argument to your getJSON() call) and you populate the timeStamp array. ONLY after that success handler has been called is the timeStamp array valid.
As such, you cannot use the timeStamp array in code that immediately follows the getJSON() call (it hasn't been filled in yet). If other code needs the timeStamp array, you should call that code from the success handler or use some other timing mechanism to make sure that the code that uses the timeStamp array doesn't try to use it until AFTER the success handler has been called and the timeStamp array has been populated.
It is possible to make some Ajax calls be synchronous instead of asynchronous, but that is generally a very bad idea because it locks up the browser during the entire networking operation which is very unfriendly to the viewer. It is much better to fix the coding logic to work with asynchronous networking.
A typical design pattern for an ajax call like this is as follows:
function loadData (url){
$.getJSON(url, function(json) {
// this will execute AFTER the ajax networking finishes
var timeStamp = [];
for (var i=0;i<json.length;i++) {
timeStamp.push(json[i].TimeStamp);
}
console.log(timeStamp);
// now call other functions that need timeStamp data
myOtherFunc(timeStamp);
});
// this will execute when the ajax networking has just been started
//
// timeStamp data is NOT valid here because
// the ajax call has not yet completed
// You can only use the ajax data inside the success handler function
// or in any functions that you call from there
}
And here's another person who doesn't understand basic AJAX...
getJSON is asynchronous. Meaning, code keeps running after the function call and before the successful return of the JSON request.
You can "fix" this by forcing the request to be synchronous with an appropriate flag, but that's a really bad idea for many reasons (the least of which is that you're violating the basic idea of AJAX). The best way is to remember how AJAX works and instead put all your code that should be executed when the AJAX returns, in the right place.
Related
I have some third party library whose events I'm listening. I get a chance to modify data which that library is going to append in the UI. It is all fine until that data modification is synchronous. As soon as I involve Ajax callbacks/promises, this fails to work. Let me put an example to show case the problem.
Below is how I'm listening to a event:-
d.on('gotResults', function (data) {
// If alter data directly it works fine.
data.title = 'newTitle';
// Above code alters the text correctly.
//I want some properties to be grabbed from elsewhere so I make an Ajax call.
$.ajax('http://someurl...', {data.id}, function (res) {
data.someProperty = res.thatProperty;
});
// Above code doesn't wait for ajax call to complete, it just go away and
renders page without data change.
// Yes I tried promises but doesn't help
return fetch('http://someurl...').then(function (data) {
data.someProperty = res.thatProperty;
return true;
});
// Above code also triggers the url and gets away. Doesn't wait for then to complete.
});
I cannot change/alter the third party library. All I have is to listen to event and alter that data.
Any better solutions. Nope. I can't use async/wait, generators, because I want to have it supported for ES5 browsers.
You cannot make a synchronous function wait for an asynchronous response, it's simply not possible by definition. Your options pretty much are:
BAD IDEA: Make a synchronous AJAX request. Again: BAD IDEA. Not only will this block the entire browser, it is also a deprecated practice and should not be used in new code, or indeed ever.
Fetch the asynchronous data first and store it locally, so it's available synchronously when needed. That obviously only works if you have an idea what data you'll be needing ahead of time.
Alter the 3rd party library to add support for asynchronous callbacks, or request that of the vendor.
Find some hackaround where you'll probably let the library work with incomplete data first and then update it when the asynchronous data is available. That obviously depends a lot on the specifics of that library and the task being done.
Does the gotResults callback function really need to return anything else than true? If not, then you could just write regular asynchronous code without this library knowing about it. Let me explain myself by rewriting your pseudocode:
d.on('gotResults', function (data) {
// If alter data directly it works fine.
data.title = 'newTitle';
// Above code alters the text correctly.
//I want some properties to be grabbed from elsewhere so I make an Ajax call.
$.ajax('http://someurl...', {data.id}, function (res) {
data.someProperty = res.thatProperty;
// Above code doesn't wait for ajax call to complete, it just go away and
// EDIT: now it should render properly
renders page without data change.
// Yes I tried promises but doesn't help
return fetch('http://someurl...');
// Above code also triggers the url and gets away. Doesn't wait for then to complete.
}).then(function (data) {
data.someProperty = res.thatProperty;
// maybe render again here?
}).catch(function(err) {
handleError(err); // handle errors so the don't disappear silently
});
return true; // this line runs before any of the above asynchronous code but do we care?
});
I'm completely new in javascript and I'm trying to understand its asynch nature. For this purpose here is my sample code :
$("#calculate-similarity").click(function(){
// assume input is an array whose length is larger than 0
var requestData={"uris":input,"limit":100};
client=new Ajax(requestData);
alert('inside .click function');
})
Ajax=function(requestData){
alert('inside ajax');
$.ajax({
url: 'http://localhost:8080/',
type:'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(requestData),
xhrFields: {
withCredentials: true
}
}).done(function(data) {
$("#ws-results").children().detach();
$("#ws-results").append('<table id="my-final-table"><thead><th>fname</th><th>furi</th><th>sname</th><th>suri</th><th>similarity</th></thead><tbody></tbody></table>');
$('#my-final-table').dynatable({
dataset: {
records:data
}
});
});
}
Now, above, I'm creating new Ajax() and inside of it, I'm making a ajax request. As far as I know its asynch event. Therefore, I though that, this request should be completed first of all, and then my other javascript lines (alert('inside .click function')) should be executed. In other words, I would expect :
1) alert inside ajax
2) show my datatable on the browser
3) alert inside .click function
However, I got with the following order :
1) alert inside ajax
2) alert inside .click function
3) show table on the browser
So, what do you suggest me to understand these concepts ? I've a solid background with several programming languages like c++ and java but this is my first time with web development and javascript.
EDIT
If I modify my .click function like below, do you say first of all always 10000 times hello will be printed out and then table will be shown ? Or table would be shown somewhere at the middle of logging ? I mean when the response comes, engine should wait first in order to show it ?
Modified code : (Let's remove all of the alert statements)
$("#calculate-similarity").click(function(){
// assume input is an array whose length is larger than 0
var requestData={"uris":input,"limit":100};
client=new Ajax(requestData);
for(var z=0;z<10000;z++){
console.log(z+'hi!');
}
})
As far as I know its asynch event. Therefore, I though that, this request should be completed first of all, and then my other javascript lines should be executed.
That is exactly the opposite of what it means.
The Ajax function will run. It will trigger an HTTP request. The Ajax function will finish. alert will run.
At some point in the future, the HTTP response will arrive and the done event handler will fire.
This is exactly the same principle as:
alert(1);
$("#calculate-similarity").click(function(){ alert(2); });
alert(3);
JavaScript doesn't wait for you to click on calculate-similarity before firing alert(3).
If I modify my .click function like below, do you say first of all always 10000 times hello will be printed out and then table will be shown ? Or table would be shown somewhere at the middle of logging ? I mean when the response comes, engine should wait first in order to show it ?
JavaScript won't interrupt a running function in order to execute a different (event handler) function. It will wait until it isn't busy before it goes looking for events.
new Ajax is object instantiation and it's synchronous. Therefore you get inside ajax as the first result because it happens when your Ajax object is instantiated, not to be confused with when the Ajax request is fired.
alert is executed synchronously, so that's the second thing you get.
$.ajax which wraps around XMLHttpRequest, responsible for firing the actual ajax request, is the only async part in your code and its result, which is encapsulated inside done, is what you get last.
In other words, I think the confusion comes from the fact that you introduce another layer of abstraction called new Ajax() which provide little actual value and a lot of confusion :P. inside ajax signal inside the instantiation of your Ajax object, not the firing of the actual request.
I'll try my best to explain it. Think of this more as an analogy, it's not exactly what's going on but I think it might help you understand:
alert('inside ajax'); - this is a blocking call, it will run and wait for you to click OK.
Then when you call Ajax, what you're essentially doing is saying "go make this web request when you have a chance, and when it finishes call my done method." That's a network operation. It could finish in 1 second, it could take many seconds. Rather than freezing up the whole browser, this is done "in the background." So that makes the UI remains responsive. At some point in the future the network request will finish. When it does, the function you specified in done will get called to let you know it finished. Think of making the Ajax request as adding it to a queue rather than actually connecting to the network. When the browser gets to it it will execute your request and wait for the server to respond. When it does, it will signal you to let you know.
Next you alert('inside .click function'); which displays the alert and blocks.
Like I said, that's not a technically accurate description of what's going on, but I'm hoping it helps you understand the principle of it.
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.
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.
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).
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What does Asynchronous means in Ajax?
jQuery ajax return value
Trying to do a function that contains a jQuery function (getJson()) as part of it, but when I run it, my javascript function returns before calling the getJson(). I want to know why the getJson is not being called in order, and how to fix it.
function getUsers(screen_name){
user_list=[]
var id_list =[]
$.getJSON(url, function(json)
{
//do stuff here, I have breakpoint #1 here
});
return user_list //breakpoint #2 is here
}
When running it from the console: getUsers('myUser') it firsts gets to breakpoint #2 and then to breakpoint #1.
getJSON() is asynchronous by default. That means that calling it just starts the operation and the rest of your javascript continues to run. Sometime later, the asynchronous operation finishes and the success handler is called with the returned data.
Any code that needs access to the returned data must either be in the success handler or in a function that you call from the success handler. You cannot use an asynchronous function and just return the user_list like you are trying to.
Instead, you will have to rethink how your code is organized so that the code that uses the user_list is in the success handler or is called from the success handler.
getJSON() can be set to be synchronous, but that is generally a bad way to program in javascript because it locks up the browser for the duration of the networking call which is generally a bad user experience. Instead, if you write the code properly to deal with it being aschronous, then the browsers stays completely interactive for the full duration of the ajax call.
I have a question as to how client-side code is processed along with server-side responses.
I have some code (too complex and long to post here) that when it runs, calls a function which runs some server-side code using a HTTPRequest Object, and returns a string to the page that the function was called from. For some reason, I think that the client-side code is being processed, the string is returned (too late) and my code is failing because of it. For example, I call my function with the HTTPRequest, next line I try to display the returned value (the string from the HTTPRequest) in an alert, and the alert shows up as blank. A few lines later in the code though, the same alert shows up with the value returned. So, basically, I am under the impression that the first client-side alert is being processed so that it displays a string which has not yet been returned, whereas the second alert was processed later, (ergo. giving the server time to process the request) and displaying the requested string. Does this theory sound logical? Will client-side code run, regardless of whether or not a HTTPRequest was completed? If so, are there any ways to prevent the client-side code from executing until a response is received from the server?
An HTTP Request is asynchronous. That means your code is going to send it and continue on with it's execution. You need to set up a callback function that takes the data returned by the XHR request, and uses that data in some way.
You need to bind an anonymous function to the onreadystatechange event of the XmlHttpRequest object so:
//xhr is an instance of the XmlHTTPRequest object that you have opened correctly
xhr.onreadystatechange = function(){ //4 means the request was successful
if (xhr.readyState === 4){
//Your code here
}
}
You need to make sure that your bit of code that attempts to display / act on the returned value is within the scope of the ajax routine. That's the only way to guarantee that the response will not be acted upon until the request has been completed (whether successfully or not). For example, if you are using jQuery:
CORRECT
jQuery.get('ajax/ajax.getSomeData.php',{id:id}, function(data) {
$('#myDIV').html(data);
});
INCORRECT
jQuery.get('ajax/ajax.getSomeData.php',{id:id}, function(data) {});
$('#myDIV').html(data);