I'm trying to add another asynchronous call to the contract of an existing Deferred before its state is set to success. Rather than try and explain this in English, see the following pseudo-code:
$.when(
$.ajax({
url: someUrl,
data: data,
async: true,
success: function (data, textStatus, jqXhr) {
console.log('Call 1 done.')
jqXhr.pipe(
$.ajax({
url: someUrl,
data: data,
async: true,
success: function (data, textStatus, jqXhr) {
console.log('Call 2 done.');
},
})
);
},
}),
$.ajax({
url: someUrl,
data: data,
async: true,
success: function (data, textStatus, jqXhr) {
console.log('Call 3 done.');
},
})
).then(function(){ console.log('All done!'); });
Basically, Call 2 is dependent on the results of Call 1. I want Call 1 and Call 3 to be executed in parallel. Once all 3 calls are complete, I want the All Done code to execute. My understanding is that Deferred.pipe() is supposed to chain another asynchronous call to the given deferred, but in practice, I always get Call 2 completing after All Done.
Does anyone know how to get jQuery's Deferred to do what I want? Hopefully the solution doesn't involve ripping the code apart into chunks any further.
Thanks for any help.
UPDATE: Please see my follow up question.
You have to call .pipe on the deferred object returned by the first $.ajax call, not inside its success callback (this does not have any effect at all):
$.when(
$.ajax({
// ...
}).pipe(function() {
// return a deferred object from .pipe
return $.ajax({
// ...
});
}),
$.ajax({
// ...
})
).done(function(){ console.log('All done!'); });
.pipe returns a new deferred object which only gets resolved once both, the original deferred object and the returned one get resolved.
Related
My original task is the following:
Execute jQuery.ajax()
On success, do some extra checks on the data returned by the server
If these checks fail, return a rejected promise.
After googling and stackoverflowing, the following solution was born:
$.ajax({
type: "POST",
url: "some url",
data: somedata,
error: somefunction
}).then(function (data) {
if (!ajaxSuccess(data, null, null)) {
return new $.Deferred().reject().promise();
}
return data;
});
(Function ajaxSuccess does perform the checks mentioned above in paragraph 2.)
What I dislike about this code is the last line:
return data;
IMHO, it would be much more correct to return the original ajax jqXHR object, since the result of the code will be used by a third-party library js-Grid.com, which expects a jqXHR/promise.
So the questions are:
Is it more correct to return the original ajax jqXHR rather than parsed JSON?
How to return the original jqXHR?
Thanks very much in advance.
opinions are irrelevant - do what you require for your code
jQuery has a very loose interpretation of how Promises work, especially with AJAX family of functions, the callback function passed to .then actually receives THREE arguments
So, you could do:
$.ajax({
type: "POST",
url: "some url",
data: somedata,
error: somefunction
}).then(function (data, textStatus, jqXHR) {
if (!ajaxSuccess(data, null, null)) {
return new $.Deferred().reject().promise();
}
return jqXHR;
});
I have a click event that fires off 3 ajax calls:
$("#button").click(function(e) {
e.preventDefault();
$.ajax(call1);
$.ajax(call2);
$.ajax(call3);
some_function() //should fire off AFTER all ajax calls are complete
});
Is there a way for me to confirm all ajax calls have been fired BEFORE firing off my some_function() function?
Thanks in advance!
You can use $.when
Provides a way to execute callback functions based on one or more objects, usually Deferred objects that represent asynchronous events.
$.when($.ajax(call1), $.ajax(call2), $.ajax(call3))
.done(function () {
some_function();
});
If (for some reason) you have an array of promises, then you may call this method using Function.prototype.apply():
$.when.apply($, ajaxArray)
.done(function () {
some_function();
});
I suggest you to use async: false and put the $.ajax inside another ajax, somelike this...
$.ajax({
async: false,
// ...
complete: function() {
$.ajax({ // second ajax
async: false,
// ...
complete: function() {
$.ajax({ // second ajax
async: false,
// ...
complete: function() {
some_function();
}
});
}
});
}
});
It depends if you require success responses, but consider the following:
$.ajax({
url: "http://some.url.example.com/endpoint",
})
.always(function (data){
// Process the data
$.ajax({
url: "http://some.url.example.com/endpoint2",
})
.always(function (data2){
// Process the data
$.ajax({
url: "http://some.url.example.com/endpoint3",
})
.always(function (data) {
someFunction();
});
});
});
There is a lot more reading that could be done about jQuery deferred objects and ES6 Promises.
If you wish to set a timeout and don't care about the result, set the timeout option `$.ajax({url: "http://some.url.example.com/endpoint", timeout: 500})
OR
Set a variable in each and use window.setTimeout to check when they've all been set, but that is horrible.
I have an ajax call that might take a bit to complete. I don't want to use async:false because I want it to stay non blocking code. So I decided to use Q. The problem is I don't understand how ca I extract the json that came back from Q.when($.ajax...). I'm new to Q.
In this example I would like the variable to hold the json that came back from the server:
var res = Q.when($.ajax({
type: "POST",
url: "GetData.asmx/GetMembersList",
contentType: "application/json; charset=utf-8",
dataType: "json"
}));
return res;
With asynchronous calls you can't just assign the result to a variable, because that result won't exist until sometime in the future. Q.when does not return the result, it returns a promise object that will eventually resolve with a result.
If there is only ever one thing you want to do with the JSON you could just inline a .then call to get the result.
Q($.ajax({
type: "POST",
url: "GetData.asmx/GetMembersList",
contentType: "application/json; charset=utf-8",
dataType: "json"
})).then(function (res) {
// res now contains the JSON
});
However the real power of promises comes with the fact that you can pass them around and use them later.
function getMembersList() {
return Q($.ajax({
type: "POST",
url: "GetData.asmx/GetMembersList",
contentType: "application/json; charset=utf-8",
dataType: "json"
}));
}
var membersList = getMembersList();
membersList.then(function (res) {
// once the AJAX call completes this will
// run. Inside this function res contains the JSON
return res; // pass res to the next chained .then()
}).then(function (res) {
// you could chain another then handler here
});
// do some other stuff
membersList.then(function (res) {
// you could also add another then handler later too
// even long after the AJAX request resolved and this
// will be called immediately since the promise has already
// resolved and receive the JSON just like the other
// then handlers.
});
You don't need to use Q if you don't have other reasons for using it, since version 1.5 jQuery returns a deferred object from AJAX calls. A Deferred is similar to a promise. Q does offer more power and jQuery's promises/deferreds don't exactly implement the Promises/A standard, potentially causing problems with error handling. For something simple like an AJAX call jQuery promises are usually good enough if you are already using jQuery anyway.
var membersList = $.ajax({
type: "POST",
url: "GetData.asmx/GetMembersList",
contentType: "application/json; charset=utf-8",
dataType: "json"
});
membersList.then(function (res) {
// res now contains the JSON
});
Here are some examples from the q documentation about using with jQuery ajax.
return Q(jQuery.ajax({
url: "foobar.html",
type: "GET"
})).then(function (data) {
// on success
}, function (xhr) {
// on failure
});
// Similar to jQuery's "complete" callback: return "xhr" regardless of success or failure
return Q.promise(function (resolve) {
jQuery.ajax({
url: "foobar.html",
type: "GET"
}).then(function (data, textStatus, jqXHR) {
delete jqXHR.then; // treat xhr as a non-promise
resolve(jqXHR);
}, function (jqXHR, textStatus, errorThrown) {
delete jqXHR.then; // treat xhr as a non-promise
resolve(jqXHR);
});
});
https://github.com/kriskowal/q/wiki/Coming-from-jQuery
Hope that helps.
Using vktemplate isn't quite working when I try to use jquery deferreds. Since the vktemplate makes an ajax call of its own, the deferred gets resolved before vktemplate completes its work, and its optional callback. How can I set up vk so that the promise doesn't get resolved until after these two things happen?
$(document).on('click', '.ajax', function() {
$.when(ajax1('<p>first</p>'),
ajax2('<p>second</p>'),
ajax3('<p>third</p>'))
.then(function(results1, results2, results3) {
console.log(results1);
$('.document').append(results1);
$('.document').append(results2);
$('.document').append(results3);
alert('all ajax done');
});
});
function ajax1(data) {
$.ajax({
type: 'post',
url: 'templates/test_template.tmpl',
data: "data=" + data,
dataType: 'json',
success: function (returnedData) {
$('#resultsDiv').vkTemplate('templates/test_template.tmpl', returnedData, function () {
//vk callback
//possibly call my resolve here?
});
}
});
}
function ajax2(data){//more of the same}
Since vkTemplate returns nothing you need to manually create a deferred and resolve it in success callback with required data.
function ajax1(data) {
var dfd = $.Deferred();
$.ajax({
type: 'post',
url: 'templates/test_template.tmpl',
data: "data=" + data,
dataType: 'json',
success: function (returnedData) {
$('#resultsDiv').vkTemplate('templates/test_template.tmpl', returnedData, function (el, data, context) {
dfd.resolveWith(context, [$(el)]);
});
}
});
return dfd.promise();
}
Here is some code I'd like to execute. I'd like to wait for AJAX response so I can return something from the server. Any way to achieve this?
function functABC(){
$.ajax({
url: 'myPage.php',
data: {id: id},
success: function(data) {
return data;
}
});
//Wait for AJAX (???)
}
var response = functABC();
When using promises they can be used in a promise chain.
async=false will be deprecated so using promises is your best option.
function functABC() {
return new Promise(function(resolve, reject) {
$.ajax({
url: 'myPage.php',
data: {id: id},
success: function(data) {
resolve(data) // Resolve promise and go to then()
},
error: function(err) {
reject(err) // Reject the promise and go to catch()
}
});
});
}
functABC().then(function(data) {
// Run this when your request was successful
console.log(data)
}).catch(function(err) {
// Run this when promise was rejected via reject()
console.log(err)
})
New, using jquery's promise implementation:
function functABC(){
// returns a promise that can be used later.
return $.ajax({
url: 'myPage.php',
data: {id: id}
});
}
functABC().then( response =>
console.log(response);
);
Nice read e.g. here.
This is not "synchronous" really, but I think it achieves what the OP intends.
Old, (jquery's async option has since been deprecated):
All Ajax calls can be done either asynchronously (with a callback function, this would be the function specified after the 'success' key) or synchronously - effectively blocking and waiting for the servers answer.
To get a synchronous execution you have to specify
async: false
like described here
Note, however, that in most cases asynchronous execution (via callback on success) is just fine.
The simple answer is to turn off async. But that's the wrong thing to do. The correct answer is to re-think how you write the rest of your code.
Instead of writing this:
function functABC(){
$.ajax({
url: 'myPage.php',
data: {id: id},
success: function(data) {
return data;
}
});
}
function foo () {
var response = functABC();
some_result = bar(response);
// and other stuff and
return some_result;
}
You should write it like this:
function functABC(callback){
$.ajax({
url: 'myPage.php',
data: {id: id},
success: callback
});
}
function foo (callback) {
functABC(function(data){
var response = data;
some_result = bar(response);
// and other stuff and
callback(some_result);
})
}
That is, instead of returning result, pass in code of what needs to be done as callbacks. As I've shown, callbacks can be nested to as many levels as you have function calls.
A quick explanation of why I say it's wrong to turn off async:
Turning off async will freeze the browser while waiting for the ajax call. The user cannot click on anything, cannot scroll and in the worst case, if the user is low on memory, sometimes when the user drags the window off the screen and drags it in again he will see empty spaces because the browser is frozen and cannot redraw. For single threaded browsers like IE7 it's even worse: all websites freeze! Users who experience this may think you site is buggy. If you really don't want to do it asynchronously then just do your processing in the back end and refresh the whole page. It would at least feel not buggy.
nowadays I prefer using async function and await syntax
async function functABC(){
await $.ajax({
url: 'myPage.php',
data: {id: id},
success: function(data) {
return data;
}
});
//Wait for AJAX
}
Try this code. it worked for me.
function getInvoiceID(url, invoiceId) {
return $.ajax({
type: 'POST',
url: url,
data: { invoiceId: invoiceId },
async: false,
});
}
function isInvoiceIdExists(url, invoiceId) {
$.when(getInvoiceID(url, invoiceId)).done(function (data) {
if (!data) {
}
});
}
async: true
When we request for some data to a server, then server will may take some time to return a response. Now During this time browser interpreter resume execution it will not wait for response and continues it's execution. So that response may print second and other code output will be print first. This happens due to async is set to true. Now question arise that what this parameter does. async means asynchronously. This attribute tells to interpreter that do not does execution sequentially.
async: false
Means forcing that complete execution of this call/code first and then go for next. So it is depends on your requirement that how you use this attribute.
Example with async:
function ayncfunction() {
$.ajax({
url: 'abc.php',
data: {id: id},
async: true,
success: function(repsonse) {
return repsonse;
}
});
}
Example without async
function ayncfunction(){
$.ajax({
url: 'abc.php',
data: {
id: id
},
async: false,
success: function(repsonse) {
return repsonse;
}
});
}
use async:false attribute along with url and data. this will help to execute ajax call immediately and u can fetch and use data from server.
function functABC(){
$.ajax({
url: 'myPage.php',
data: {id: id},
async:false
success: function(data) {
return data;
}
});
}
Method 1:
function functABC(){
$.ajax({
url: 'myPage.php',
data: {id: id},
success: function(data) {
return data;
},
complete: function(){
// do the job here
}
});
}
var response = functABC();
Method 2
function functABC(){
$.ajax({
url: 'myPage.php',
data: {id: id},
async: false,
success: function(data) {
return data;
}
});
// do the job here
}