When my site first initializes, it queries a server to get back some data. I can't lay anything out on the page until this data gets back. With d3.js, I can use d3.json() to get my data, but because it's asynchronous, I need to put the entire page logic in the callback function. How do I request the data and wait for it to come back?
You're basically doing it the only way. The callback function has to be the one initiating the rest of your code. You don't need all your code in the callback function though, you can introduce indirection. So the callback function will call another function inside which would be what is currently in your callback function.
Using synchronous requests in JavaScript is not recommended as it blocks the whole thread and nothing gets done in the meantime. The user can also not interact well with the webpage.
If it is really what you want, you can do the following (using jQuery):
var jsonData;
jQuery.ajax({
dataType: "json",
url: "jsondatafile.json",
async: false
success: function(data){jsonData = data}
});
However it is not recommended, even by jQuery, as explained here the jQuery.ajax() documentation:
The first letter in Ajax stands for "asynchronous," meaning that the operation occurs in parallel and the order of completion is not guaranteed. The async option to $.ajax() defaults to true, indicating that code execution can continue after the request is made. Setting this option to false (and thus making the call no longer asynchronous) is strongly discouraged, as it can cause the browser to become unresponsive.
As a final note, I don't see what prevents you from using whatever function there is in the success attribute in an asynchronous way. Most of the times changing your design to use async requests will be worth it. By experience, debugging a page that uses synchronous requests is a pain (especially when the requests don't get answered...).
Related
I need a Javascript function that serves the purpose shown below. I simply want to wait on the response from the server.
console.log('Before getting the city name.');
zip_code = '60601';
city_name = function_that_slowly_gets_city_name_from_server(zip_code);
console.log(city_name);
console.log('After getting the city name.');
Output in console:
Before getting the city name.
Chicago
After getting the city name.
I do not want the answer ('Chicago') sent to the console in a callback function. I understand that async:false is now taboo with $.ajax(), but I still need for it to work as shown above. I cannot find posts that provide a consistent, straightforward answer.
FOLLOW UP:
I've found many answers on StackOverflow that say synchronous calls are evil. Yet, is there a way to do it anyway?
Based on your comment, your use-case is a quick method of disabling user-interaction while the AJAX call is occurring to ensure the user can't do anything bad (e.g. start a duplicate request/race condition or navigate to a different part of the app, etc.). So maybe locking the thread ain't such a bad idea then, especially for an internal app that doesn't need a ton of frills?
But Here's the Problem:
The user can continue to queue events even during a locked thread. That means that any actions the user takes while a synchronous request is occurring (such as submitting a form) will continue to line up in the background, and will then begin firing as soon as the initial request is finished. So the threat of your user double or triple clicking out of impatience (or even just accidentally) -- and as a result causing duplicate calls to the database -- is very real and likely (for reference, I can double click in ~120ms pretty easily).
The same thread is also responsible for things that might surprise you, such as certain browser-level hotkeys or even exiting the tab at all, meaning yes, you could actually significantly delay the user from closing the application, though that's not likely for a low-traffic database. However, it's certainly not impossible, and it's definitely not desirable, even for an application that doesn't need all the frills of a commercial product.
So What Should I Do as a Quick Solution Instead?:
Well if you still need a quick solution that can effectively freeze the entirety of your application in one go, then depending on your existing code, this shouldn't be too bad either.
Make the request async, as is the default and standard. But before that request fires, select all elements typically in charge of event handling, disable them with the "disabled" attribute, and then re-enable them in the callback. Something like this:
var userStuff = $("input, button, submit, form");
userStuff.prop("disabled", true);
$.ajax({
// other ajax request settings ...
// ...
// ...
complete: (data) => {
userStuff.prop("disabled", false);
}
});
The elements contained within userStuff are just common elements that typically have some event-handling to them. It's up to you to determine if those elements are sufficient for your application, or if your application is so large that such a query could itself have a performance impact. But assuming that checks out, this will prevent the user from interacting with/queueing anything until the request has finished.
I Don't Care. Give me the Sync:
Well in that case, why not just use async: false as mentioned in your OP? I'm somewhat speculating here, but I believe it's not just async: false that's deprecated, but all means of synchronous XMLHttpRequest (which I believe $.ajax still uses under the hood), and I don't think there's any other synchronous alternative to that. So anything you do with synchronous network in mind is going to be evil, but at least in Chrome 89.0, $.ajax({async: false}) still works for me.
I have some doubt in Asynchronous and synchronous terms in ajax.
How Asynchronous process will work?
Can you please let us know about this terms?
Synchronous ( async: false ) – Script stops and waits for the server to send back a reply before continuing.
Asynchronous ( async: true ) – Async requests occur on a background thread, meaning that the UI is not going to be blocked while the request is processing.
Why AJAX has called Asynchronous? Can you please describe any one
please?
asynchronous is the best because the client and the server run independently of each other for the duration of the function call.
During a normal function call, you make the call, and the calling function doesn't get to execute again until the function call finishes and returns. The caller and the callee are always synchronized.
During an asynchronous function call, you make the call, and then control returns immediately to the caller. The callee then returns a value some indeterminate amount of time later. That "indeterminate amount of time" means the caller and callee are no longer synchronized, so it's asynchronous.
Meanwhile you can make multiple request if you set async:true because control returns immediately, it will not wait like synchronous call till it receives response from server, here is picture which give clear idea.
Controller:
The code that handles post back has a db call in biz layer that is long running. After 30 minutes, the browser showed the error message from the ajax call, however my db logs showed that the db method was still running - ran way past the 30 min mark.
My ? is how does the ajax error get raised when it wasn't raised in the controller [log4j did not show any errors trapped] as the controller was still waiting for feedback from the biz layer.
Does adjusting the timeout in tomcat help? I assume not as the app was still processing
My View:
function runAjax(){
$.ajax({
type: "POST",
url: "Test.html",
data: { testparam1,testparam2},
success: function(data){
document.getElementById("processdata").innerHTML="Success";
},
error: function(request){
document.getElementById("processdata").innerHTML="Error";
}
});
}
The browser, aka JavaScript, is not going to wait forever for a response. After some time (read 30min in this case), it will give up on the request, thinking the server is not responding. HTTP is not really set up to handle requests that take > 30min, at least not through the normal means.
There are some options. First, you could optimize whatever you are doing in the backend to make it faster. I mean, if it's taking 30+ min for a query to run, then you may need to rethink your SQL approach a bit.
Second, you could simply break up the steps, so that you can run each step, verify, then run the next. Depending on what you are doing, this may open up the possibility to do some work in parallel, speeding up the process. The challenge here would be in rolling back in the case when something failed.
Third, you could implement a Pub/Sub model. There are several frameworks out there to do Pub/Sub for JavaScript. I have personally used Atmosphere, which has a nice jQuery plugin and falls back to more HTTP conventional methods when the more advanced methods are not available in the browser. In this model, your View would submit the request, the backend would queue up the work and tell the View to subscribe to a particular queue/channel to get the result. The View can simply wait for the response.
Forth, you could post the request, have an interrum page that simply keeps refreshing via JavaScript until the backend says "Ok, we are done!". Lots of older web applications used to do this for long-running transactions.
I am sure there are probably 1000 more options you could use, but if your request will always take that long to run, I think AJAX is not the tool for you.
I have a page which fires Ajax requests for validations at server side. I need to perform an action when all the ajax requests have finished loading or are completed.
For this, I am using Ext.Ajax.isLoading() in a recursive function in following way:
function chechValid(){
if(Ext.Ajax.isLoading()){
checkValid();
}else{
//Code for Action 1
}
}//EOF
checkValid();
//Code for Action 2
The problem is that when I do this, browsers give the following errors:
Mozill FF - too much recursions
IE - Stack overflow at line:18134
If this recursion is a heavy thing for the browsers, then how to perform a task when all the Ajax requests have finished loading?
Using delay is not what I want as, if delay is used then browser begins executing the other code (like 'Code for Action 2' as shared above) which is not what is expected.
The main aim is that the browser shouldn't execute anything unless all the Ajax requests are complete and once completed then it should perform a particular action.
Any suggestions/help on this one?
Thanks in Advance.
PS: Using ExtJs 4.0.7
(Updated)More Detail about the actual situation:-
Here is brief description of the situtaion being faced - There is a form, in which I need to perform server side validations on various fields. I am doing so by firing an ajax request on blur event. Depending upon the server response of validation Ajax fired on blur, fields are marked invalid and form submission is not allowed. (Avoiding 'change' event as that causes alot of overhead on server due to high number of Ajas requests and also leads to fluctuating effects on a field when response from various such Ajax requests are received).
Things are working fine except in one case - when user modifies the value of a field and instead of 'tab'bing out from the field she directly clicks at the save button. In such a case, though, the blur event gets fired but the processing of 'Save' doesn't wait for Ajax Validation response and submits the form. Thus, I somehow need to check if Ajax requests have finihed loading and the process the saving of form. requestComplete would unfortunately not serve the purpose here. And if try using the recursion, then of course, the browser is hung due to high usage of resources. Same case occurs if I try using a pause script work around ( as shared here - Javascript Sleep).
Any possible workaround for this one?
TIA
Your method will lead to infinite recursion.
A better way is to register a callback function in Ext.Ajax.requestcomplete, something like this (not tested):
Ext.Ajax.on('requestcomplete', function(conn, response, options) {
if (!Ext.Ajax.isLoading()) {
//your action...
}
}
};
Unless I am misunderstanding the issue couldn't you create a couple of globals. I know globals are bad, but in this case it will save you quite a bit of headache. One global would be "formReady" and initially set it to false, the other would be "ajaxActive" and set to false. You would also add an onSubmit method that would validate that "formReady" was true and if not alert the user that validation was occurring (or you could set a timeout for form submission again and have a second validation that checks to see if "ajaxActive" is true). When the AJAX call is made it would set the variable "ajaxActive" to true and once complete would set formReady to true. You could also potentially resubmit the form automatically if the response from the AJAX was that the form was good.
Ext.Ajax.request() returns a transaction object when you call it, which is unique and allows you to recognise and abort specific Ajax requests.
By just calling Ext.Ajax.isLoading() without a specified transaction object, it defaults to the last request, which is why you have to call it recursively at the moment.
If it were me, I'd create an array of these transaction objects as you fire them off, and pass each of those in as optional parameters to the Ext.Ajax.isLoading() function to check if a particular request has finished. If it has, you can remove that transaction object from the array, and only progress with the save when your array is empty.
This would get round your recursion problem, since you've always got a finite number of requests that you're waiting on.
if (Object.keys(Ext.Ajax.requests).length === 0) console.log("No active requests");
I feel ackward asking these fundamental questions given that I am not exactly new to web development. But I want to double-check my assumptions nevertheless...
I'm building the recording of unique image views in my application. When a user (not a bot) visits an image page, an Ajax call is made to a back-end process that collects the session info, compares for duplications and stores the visit. I have all my javascript references as well as this call at the bottom of the HTML, just before the </body> element:
$.get(basepath + "image/1329/record/human", function(data){
console.log("Data Loaded: " + data);
});
By default, the call to $.get is made asynchronous. Yet I want to test the following assumptions:
Is it correct that this method ensures that the call to the view recording script is non-blocking for the rest of the UI?
Is it correct that the back-end script will finish once called, regardless of whether the user navigates to another page?
According to jQuery .get reference...
This [$.get()] is a shorthand Ajax function, which is equivalent to:
$.ajax({ url: url, data: data,
success: success, dataType: dataType
});
And $.ajax is asynchronous (i.e. non-blocking) by default, that's what the A in Ajax means.
Also, back-end server code is started in the moment the server receives the request and then runs independently of the client staying on the page or not, unless you implement some kind of mechanism to stop the running service which I suppose you did not.
God bless!
The jQuery.get request you're making is asynchronous and will not block the DOM or other JavaScript from continuing. The get function is a shorthand method which uses jQuery.ajax.
The second question I don't have a solid answer for -- I expect it may depend more on how the back-end code is structured and whether it's told that the session/request has terminated.
API:
jQuery.get()
jQuery.ajax()
that is correct on both counts