Continue function after ajax request has been completed - javascript

I was wondering if it was possible to have a function call a function that has an ajax request, and continue executing when the ajax request finished. Here is example pseudo code.
function func1(){
//do things
func2();
//**How would I get this code to execute after the ajax request is finished.
}
function func2(){
$.ajax({
url: "test.html",
context: document.body,
success: function(){
//do some things
}
});
I do not want to execute everything in a callback function, as this function is called many times in a loop.
Thanks!

You have two choices.
Use a callback function for the processing that happens after the AJAX call.
Use a synchronous "JAX" call ... remember, the A in AJAX is Asynchronous.
Otherwise, there's not a good way to accomplish what you describe.

Related

Does a ajax callback function guarantee synchronous execution?

For example:
ajaxCall() {
$.ajax({
...
...
success: function(response) {
event2();
}
});
}
If we have a call like:
event1();
ajaxCall();
event3();
Would it be always guaranteed that the order of execution of events be
event1() then event2() and event3() without setting the async flag ?
AJAX is Asynchronous JAX :) There's your answer.
If you want to make a synchronous call, you need to set the async: false flag. But then the success callback won't be called at all and you would need to put the event2(); line just below the $.ajax call.
Also see Mike C's answer. The synchronous calls are deprecated.
In general, you're right if you set async to false. However, synchronous AJAX has been deprecated and jQuery officially dropped support for it after v1.8.
So I would suggest you avoid trying to use synchronous AJAX requests.
No.
The callback function will fire when the event that triggers it (i.e. the HTTP response) happens.
A function you call immediately after you assign the callback will still be called immediately.
The order of execution will still be:
event1();
ajaxCall();
$.ajax();
event3();
success();
event2();

Can anyone explain me the execution process of functions in jquery

I have a small doubt on Execution cycle of function in jquery. I'm trying to do some stuff with js, And in my script I have one custom function that calls on click of a button. What happens is, when I call the function it will make some ajax call and assigns the result to a variable. According to my knowledge after the execution of the function next statement should execute. But here what happens is after function call before completing the function execution next statements are executing.
Structure of my script is :
var variable=false;
function myfunction(e){
.....
.....
$.ajax({});
.....
console.log('inside : '+variable);
}
$('#button').click(function(){
....
....
myfunction(n);
console.log('called : '+variable);
....
$.ajax({});
....
....
});
Console output:
Ajax call from the function;
called : false
Ajax call from called function;
inside : true
Can anyone explain this stuff....
it will heppen indeed like this just beacause your custom function is an Ajax Call not a normal code.
Ajax stands for Asynchronous Javascript and XML
So, the request processing occur smultanelously that is what for ajax is used.
that is the reason, why even before compelting your function execution , the next statements are being executed. ( asynchronously)
Hope this helps..
Note: What ever the code you put in the Call back function of the ajax , they will be executed only after ajax call is completed
this is the power of js callbacks!
the js callbacks will do things after, and callbacks will run when get response! But js will not wait for the callbacks excution to continue, the following functions will run! Async is the beauty of js.
so in your js file, you make a ajax call for something. while ajax's running, the console will not wait until ajax complete!
if you want to excute the ajax function sync, you may make a config in the params {async: false}, then the console will wait until the ajax func complete then excute!
The call to .ajax:
Assigns an event handler to run a function when a response to an HTTP request is received
Sends the HTTP request
The next line of code runs immediately for the same reason that a line of code immediately after $('foo').click(...); runs before the function you pass to click.

How to stop execution of next Statements if an Async function returns any errors?

I have below couple of statements with in a javascript function.
postTransaction function is having a async call, which is calling a webservice and returns success or failure. I have two call back methods for success(transactionSuccess) and failure(transactionFailure).
Here my problem is if the service got failure i should stop executing the next statement i.e return requestDetails(); I dont want to use setTimeOut function here. Any other ways to handle my situation?
function doSomeThing () {
postTransaction(objSelectedAccount,transactionSuccess,transactionFailure);
return requestDetails();
}
function requestDetails () {
return true;
}
function postTransaction () {
$.ajax('URL', {
method: "POST",
dataType: "json",
data: {},
success: function (payload) {
callBackSucces(payload);
},
error: function(xhr, statusText, ex) {
callBackFailure(xhr);
}
});
}
You can't stop the next statement from executing based on the result of an async operation. That's the whole point of async operations! You also don't want to make the ajax request a blocking request, because that will freeze the UI until the request completes -- a bad user experience that might also lead to a "script has stopped responding" alert from the browser.
The best you can do is move whatever processing you want delayed into the success handler for the ajax call. Don't think of the ajax call as something that "returns success or failure"; it doesn't actually return anything (in the JavaScript sense). Instead, think of it as something that generates either a success or a failure event at some future time and code your app to handle the events.
If requestDetails() may not be called until the transactionSuccess was called, then you may put the requestDetails into the transactionSuccess. And your function doSomehting should not be a synchronous function.
So, change your code to something like this:
function doSomething(callback) {
postTransaction(objSelectedAccount, function () {
// success and do something..
callback requestDetails();
}, transactionFailure);
}
A function, which have a asynchronous step, should also be a asynchronous function.
I hope this could help you, and please forgive my poor English..
function doSomeThing () {
postTransaction(objSelectedAccount,transactionSuccess,transactionFailure);
}
function requestDetails () {
return true;
}
function postTransaction () {
$.ajax('URL', {
method: "POST",
dataType: "json",
data: {},
success: function (payload) {
requestDetails(payload);
},
error: function(xhr, statusText, ex) {
callBackFailure(xhr);
}
});
}
OR,
use synchronous request.
There is no way to change an asynchronous operation into a synchronous operation (i.e. to "wait" for the outcome and then call or not something else).
You must rework and break down your logic into smaller parts so that the operation are done (or just started) in the "success" callback.
Note that many asynchronous operations are indeed just requests to a server and it's possible to make a synchronous request (i.e. performing a "get" blocking while wainting for the answer instead of using callbacks) but this is considered not a good idea in general because the application becomes less responsive.
Unfortunately (and for reasons I don't fully understand) Javascript doesn't expose the event dispatching primitive and thus is impossible to use what is normally done in other event-driven environments like GUIs when asynchronous is very inconventient (e.g. requesting of a confirmation) that is a "nested event loop".
The fact that you cannot build a synchronous operation from an asynchronous one is also the reason for which in node for many functions there are the equivalent Synch versions that would be impossible for the application programmer to create.

Why does jQuery.then() behave differently when using $.deferred and $.ajax

I've been trying to get my head around the jQuery Deferred object. My intention is to inspect each ajax response (success/fail). I want to do this without interfering with other code that declares a typical $.ajax().done().fail() request.
I've user the $.ajaxPrefilter() to get each ajax request before it is executed. Using the .then() method on the jqXHR object, I've managed to add a function that will be called before the .done() method placed on the original $.ajax() call
The code below will print out the following:
def done
def then
2nd ajax prefilter then
2nd ajax done
2nd ajax then
ajax done
ajax then
What I don't understand is why the prefilter step executes first. I would have expected it to have been executed last, or not at all.
The behaviour is what I want, but I don't understand why.
// this is a typical usage of deferred with two done functions added, the second via .then()
var def = $.Deferred();
def.done(function(){
document.write("def done<br>");
});
def.then(function(){
document.write("def then<br>");
});
def.resolve();
// this is a typical ajax request with a done function added, followed by another using .then()
$.ajax("/echo/json/").done(function(){
document.write("ajax done<br>");
}).then(function(){
document.write("ajax then<br>");
});
// for the third request i intercept and call the .then() method
$.ajaxPrefilter(
function( options, originalOptions, jqXHR ) {
jqXHR.then(function(data, textStatus, jqXHR){
document.write("2nd ajax prefilter then<br>");
});
});
// create a typical ajax request. these will be executed after the prefilter .then()
$.ajax("/echo/json/").done(function(){
document.write("2nd ajax done<br>");
}).then(function(){
document.write("2nd ajax then<br>");
});
Thanks in advance for any help
UPDATE: ------------
From #Bergi response, the code below demonstrates how the $.ajaxPrefilter() is called before the done().
$.ajaxPrefilter(
function( options, originalOptions, jqXHR ) {
document.write("prefilter function within $.ajax call<br>");
jqXHR.then(function(data, textStatus, jqXHR){
document.write("2nd ajax prefilter then<br>");
});
});
var functionToRunWhenDoneIsCalled = function() {
document.write("done is called function<br>");
return function(){
document.write("2nd ajax done<br>");
}
}
$.ajax("/echo/json/").done(
(functionToRunWhenDoneIsCalled)()
).then(function(){
document.write("2nd ajax then<br>");
});
This outputs:
prefilter function within $.ajax call
done is called function
2nd ajax prefilter then
2nd ajax done
2nd ajax then
Which answers my question about how the .then() method is attached to the deferred jqXHR object before the .done() method.
In your case, there is no difference between adding callbacks with .done() or with .then(). Using only .done() would be enough.
What I don't understand is why the prefilter step executes first. I would have expected it to have been executed last, or not at all.
Callbacks are executed in the order they are added to the deferred object. And the prefilter is executed inside of $.ajax, i.e. the callback is attached even before the $.ajax call returns and your done and then handlers can be attached.
All .then does if you don't return a deferred object is add another done fail and/or progress handler to the deferred object. with that in mind, it makes complete sense for the .then added in the pre-filter to execute before the one added after $.ajax() because the code in the pre-filter callback happened first. The callbacks get triggered first in first out.
What I don't understand is why the prefilter step executes first. I would have expected it to have been executed last, or not at all.
You've attached another "thing to do" to the jqXHR that is associated with the ajax request. Since it's a pre-filter, that gets attached before the standard done/fail that the ajax request uses. Handlers run in the order they were attached and the prefilter one is therefore first.
Note that since the prefilter only attached a single function in the .then() method, nothing will run if the request fails for some reason. Sounds like you'd want to have the second (failure handler) arg as well.
As for the completion order of the two different ajax requests, that is not predictable. It will just depend on which one returns first.

Setting timer after an asynchronous call returns

I have an asynchronous Ajax function which runs a command string at the server side and returns the result to the client. It calls a callback to process the result.
function ajaxCall(commandStr,callback){
var url=......//make a url with the command string
jquery.get(url,function(result){
//process the result using callback
callback(result);
});
}
The asynchronous call (ajaxCall) may take a while to be finished but I want it to do the same command after an interval (1000ms).
I want to write a function that is like this:
function ajaxCallRepeated(interval,commandStr,callback)
I tried closures like this:
function ajaxCallRepeated(interval,commandStr,callback){
//This feature uses closures in Javascript. Please read this to know why and how: http://jibbering.com/faq/notes/closures/#clSto
function callLater(param1,param2,param3){
return (function(){
ajaxCall(param2,function(out,err){
if(param3)param3(out,err);
var functRef = callLater(param1,param2,param3);
setTimeout(functRef, interval);
});
});
}
//the first call
var functRef = callLater(interval,commandStr,callback);
setTimeout(functRef, interval);
}
Then I call it like this:
ajaxCallRepeated(2000,"ls",function(result){
alert(result);
});
But it only runs the command 2 times.
How can I write a function that will reschedule itself after it is called as a callback of an asynchronous function?
PS. I want to fire another Ajax call after the previous one is finished. Also, it worth to mention that axashCallRepeated() will be called with various parameters, so several Ajax calls are running in parallel, but for each commandStr, there is only one Ajax call going on, and after the Ajax call returns, another one will be fired after X seconds.
I would not use setTimeout to trigger the second Ajax call ! Because you never know how long it will take and if it's finished !
As far as you tagged your question right and you ARE using jquery you should consider something like this:
$.ajax({
type: 'POST',
url: url,
data: data,
success: function(){
// The AJAX is successfully done, now you trigger your custom event:
$(document).trigger('myAjaxHasCompleted');
},
dataType: dataType
});
$(function(){
//somehwere in your document ready block
$(document).on("myAjaxHasCompleted",function(){
$.ajax({
//execute the second one
});
});
});
So this would ensure that the ajax post is DONE and was successful and now you could execute the second one. I know its not the exact answer to your question but you should consider on using something like this ! Would make it safer I guess :-)
The key to solve this problem is to save a reference to the closure itself and use it when scheduling the next call:
function ajaxCallRepeated(interval,commandStr,callback){
//This feature uses closures in Javascript. Please read this to know why and how: http://jibbering.com/faq/notes/closures/#clSto
function callLater(_interval,_commandString,_callback){
var closure=(function(){
ajaxCall(_commandString,function(out,err){
if(_callback)_callback(out,err);
setTimeout(closure,_interval);
});
});
return closure;
}
//now make a closure for every call to this function
var functRef = callLater(interval,commandString,callback);
//the first call
functRef();
}
It becomes easier to reason about if you separate things up a bit.
For example, the repetition logic doesn't have to know about AJAX or callbacks at all:
function mkRepeater(interval, fn, fnScope, fnArgs) {
var running;
function repeat() {
if (!running) return;
fn.apply(fnScope, fnArgs);
setTimeout(repeat, interval);
}
return {
start: function() { running = true; repeat(); },
stop: function() { running = false; }
};
}
You can use it like this:
var r = mkRepeater(2000, ajaxFunction, this, ["getStuff", callbackFn]);
r.start();
...
r.stop();

Categories

Resources