Asynchronous jquery - ajax when().then(); - javascript

I have been trying to read the documents, but I'm having a hard time understanding some concepts:
$.when(function(){
$.ajax({url:'php/Mostrarphp.php', type:'post',data: {queHacer:"MostrarUsuarios"}})
.then(function(success) {
$("#main").html(success);
},function(error) {
$("#main").html(error);
});
})
.then(function() {
console.log("test");
});
What I'm trying to do is for the first function to go into the PHP file and inside that file there is only an include to another file. After that I want to have a console log shown. (This is just practice for, when I need to run functions that retrieve data and will take longer).
The issue here is that the echo is not showing on the application, only shows what is resolved on the then (console.log("test")).
What is the correct way to have this execute the inside function and then the second one?

When you use $.when, you are creating a new promise, one that needs to be resolved. Normally, $.when is used to "combine" multiple promises into one and then run a function once all of them resolve.
What you've passed to $.when is just a function. A function that never gets run. From the docs:
If a single argument is passed to jQuery.when() and it is not a Deferred or a Promise, it will be treated as a resolved Deferred and any doneCallbacks attached will be executed immediately.
So, that means your console.log("test"); is ran, but your AJAX code is never ran.
You do not not to use $.when here. $.ajax already returns a promise, there's no need to make another one. You can just chain .then() calls.
$.ajax({
url:'php/Mostrarphp.php',
type:'post',
data: {queHacer:"MostrarUsuarios"}
}).then(function(success){
$("#main").html(success);
},function(error){
$("#main").html(error);
}).then(function(){
console.log("test");
});
EDIT: In the comments you said:
[no] matter how much time the inside execution takes to complete, the outside [should] always execute second
If this is what you want, then you will need to create another promise. You can do that and then have it resolve once your "inside" function is complete. I'd suggest wrapping your AJAX code in a function and having it return a promise that you can attach a callback to.
function ajaxCall(){
var d = new $.Deferred;
$.ajax({
url:'php/Mostrarphp.php',
type:'post',
data: {queHacer:"MostrarUsuarios"}
}).then(function(success){
setTimeout(function(){
$("#main").html(success);
d.resolve();
}, 2000);
},function(error){
$("#main").html(error);
d.reject();
});
return d.promise();
}
ajaxCall().then(function(){
console.log("test");
});

Related

Javascript: .then() in promise is not executing?

I want a script file just for accessing a JSON from a url. I want to have a method to return the JSON object from the script into a var in a separate script file then modify it accordingly. Obviously since javascript is asynchronous it fails if I simply write it out. Therefore I must use a promise:
var promise1 = new Promise(function(resolve, reject) {
access(userSearchText); //send user input to get appropriate JSON object
});
promise1.then(function(value) {
var getData = returnData(); //method that returns JSON object from the other script
alert(getData); //print out the returned JSON object
console.log("we have finished");
});
But this is not printing out anything. The alert does not occur at all and nothing is being printed in the console. I am using jquery to access the url in the other script and I have a .done after accessing it in the script for retrieving the JSON as: access.js
var sendData;
(function() {
jqxhr = $.getJSON( url, {
})
.done(function( data ) {
sendData = data;
});
})();
function returnData(){
return sendData;
}
So there should not be any asynchronous issues in the script for accessing the URL because of .done. I really don't understand why this isn't working. I inspected my page and there are no errors to be seen anywhere. Can anyone help?
promise1 never gets resolved.
In your definition of promise1, you never call the resolve() function to resolve it. Thus, it's .then() never gets called.
Manually created promises are only resolved when you explicitly call resolve() in the executor function.
If access() is itself asynchronous, then we will need to more about that function to help you do this correct. Wrapping a promise around it does not do anything to help you. If access() itself returns a promise, you should just use that promise and not wrap one around it.
Probably access() should return a promise that is resolved when it's asynchronous operation is done and then you can do:
access().then(...).catch(...);
And, not wrap it with another promise.
The sendData and returnData() stuff just looks wrong. You'd have to explain and show more context to know what exactly the recommend.

Force jQuery Deferred to wait until Ajax complete in "then" handler

I have situation where I believe I need to create a Deferred object with a "then" handler, but wait until the "then" handler has completed it's own promise before moving on.
The use case is a record object, and the above function is it's save method. The record object has an attribute called saveQueue, which is set to $.Deferred() on the record's instantiation. The resolve call on saveQueue was supposed to make sure the Deferred there is always executing every new handler attached to it as soon as it could. The idea being that you can call save several times on the record in short succession, but the calls will run one after another, and not overlap.
I am using a Deferred to enqueue Ajax calls, so that one does not run until the previous one call finished. However, from the same method, I want to return a Deferred that can be resolved/rejected by the jQuery Ajax object, like so:
record.saveQueue = $.Deferred();
self.save = function( record ){
var deferredAction = $.Deferred();
deferredAction.then(function() {
return $.post("/example_save_endpoint");
});
record.saveQueue.always(function(){
deferredAction.resolve();
}).resolve();
return deferredAction;
}
However, when I use this code, the deferredAction promise always ends up resolved, presumably because the #then handler is returning a "pending" (and thus non-rejecting) promise. Is there any way to force the Deferred to wait until the Ajax promise is complete before resolving/rejecting? Or is there another, better way to thread this needle?
Your idea might work, but
the queue must not be resolved using .resolve() every time the method is called, instead it should be initialised only with a resolved promise.
to actually queue on the record.saveQueue, it needs to be changed (overwritten) on every method call, to represent the end of the latest request.
And we don't need any deferreds for that, as we can work with the promises that $.post returns.
So use this:
var emptyQueue = $.when(undefined); // an already fulfilled promise as the start
// equivalent: = $.Deferred().resolve().promise();
function startQueue() {
return emptyQueue; // yes, this delibaretely returns a constant, the begin
// of the queue always looks the same (and is never mutated)
}
// every time you create a record, do
record.saveQueue = startQueue();
// and use that in your methods:
this.save = function(record) {
var queuedRequestResult = record.saveQueue.then(function() {
return $.post("/example_save_endpoint");
// ^^^^^^ promises chain :-)
});
// Magic happens here:
record.saveQueue = queuedRequestResult // we swap the previous queue promise for a new
// one that resolves only after the request
.then(startQueue, startQueue); // and make sure it then starts with a fresh
// queue, especially when the request failed
//.then(null, startQueue) is similar, except unnecessarily remembering the last result
return queuedRequestResult;
}
I would probably choose not to do it this way, but a deferred/promise can indeed be used as a queuing device.
You need a slight(?) variation of what you already tried.
self.queue = $.when();//A resolved promise, used to form a queue of functions in a .then() chain.
self.save = function(data) {
var dfrd = $.Deferred();//A Deferred dedicated to this particular save.
self.queue = self.queue.then(function() {
return $.post("/example_save_endpoint", data) //Make the AJAX call, and return a jqXHR to ensure the downstream queue waits for this jqXHR to resolve/reject.
.then(dfrd.resolve, dfrd.reject) //Resolve/reject the Deferred for the caller's benefit
.then(null, function() {
//Force failure down the success path to ensure the queue is not killed by an AJAX failure.
return $.when();//Return a resolved promsie, for the queue's benefit.
});
});
return dfrd.promise();//allow the caller to do something when the AJAX eventually responds
}
For explanation, see comments in code

javascript promises onSuccess handler

Is there a handler method, the counterpart of fail, something like success to really get out of that async queue and continue with your normal function calls.
Let me elaborate more. let's say
getConnection()
.then(function(connection){
return self.getRecords() //some async routine, returns promise, does reject/resolve
})
.then(function(data){
return self.getDetail() //some async routine, returns promise, does reject/resolve
})
.then(function(data){ //I'm done here calling onResult, but this onResult may call several
self.onResult(data); //other functions down the road resulting in .fail() call
}) //I want to get out of this promise queue and continue with normal functions calls
.fail(function(info){
self.onFault(info); //any error onFault causes down the road shouldn't be q problem.
})
.done(function(){ //but this gets called all the time at end no matter success or fail
//release system resource like connection etc.
})
I've tried to explain the problem in comments, basically I'm done at self.getDetail() call, once it's success, I want to get out of promise queue, reason, if self.onResult(data) had a problem way afterwards, the .fail() is gonna get triggered too as it's sort of it dependency there.
I tried putting my call in the .done() method but done() gets called no matter what, success or fail.
I've a failed routine that gets called by .fail() function but don't know if there's a success handler.
Any lateral thinking welcome.
Edit - after Barmar's comments, can we do like this. (getConnection returns a promise and does reject/resolve
connections.getConnection(function(c){
return self.getMaster(c) //async routine, returns promise, does reject/resolve
}, function(info){
self.onFault(info) //any failures in getMaster, any error in onFault shouldn't be q business
})
.then(function(data){
return self.getDetail() //async routine, returns promise, does reject/resolve
}), function(info){
self.onFault(info)} //any failures in getDetail, any error in onFault shouldn't be q business
})
.fail(function(info){ //btw any errors, onFault causes down the road shouldn't be q problem- same for above onFault calls
self.onFault(info) //do I need this after above fail routines for each call?
})
.done(function(){ //ok, once everything's done, get out of promise queue
self.onResult(self.data) //any problem onResult causes down the road, should be it's own business
}) //release routine
//two independent functions out of async queue, chain of promises etc. any error in these functions should not affect the chain of promises or call it's fail handler. chain of promises should have been done up there.
onResult: function(data) {
console.log('do something with the data');
}
onFault: function(info) {
console.log('wonder what went wrong');
}
please suggests for the edit above
My Main Main requirement, anything happen after onResult, onFault shouldn't be q library business (fail), they are supposed to handle it on their own now (afterwards)
The first function you pass into a then is in itself a success handler.
The return value of an operation like:
doSomething().then(function() { ... }) is a new promise, which you can always store inside a variable, and then use multiple, independent then calls on:
var promise = someOperation().then(function(x) {
return doSomethingWith(x);
});
promise.then(function(processedX) {
// processedX is the return value of the function used to construct `promise`
// now for something completely different
}
promise.then(someOtherFunction);
You don't need to chain indefinitely, you can always "get out of the promise chain" by storing intermediate new promises into variables and using them somewhere else, possibly multiple times, and create several independent chains.
With that, you can attach a fail handler to one and the same promise in one chain, and have none attached to it in another. In your case, you'd want to store the entire chain up to the handler calling self.onResult in a variable, use the fail handler on that variable, and continue with the rest of the code using the same variable.

jQuery: What is the difference between deferred.always() and deferred.then()?

Seems to me that both does the same thing.
Docs:
deferred.always()
deferred.then()
It would seem that deferred.then() allows you to pass two separate callbacks for success and failure, whereas deferred.always() takes n number of callbacks which will all be called regardless of the outcome of the initial event.
I would say use deferred.always() in the cases where success/failure of the initial event are not important
With .then() you can provide an individual callback for when the $.Deferred is resolved (done), and another for when the $.Deferred is rejected (fail).
.always(), on the other hand, allows you to provide a callback that always gets executed, whether the $.Deferred has been resolved or rejected. In other words, within this callback, it doesn't matter if the AJAX call has failed or has been been successfully executed.
I tend to put code in .always() when I want that code to run everytime, and independently of whether the $.Deferred was resolved successfully or not. For example, to clear an AJAX loading indicator or to hide a progress bar. Using .then() you'd have something like this:
$.get("/some/url").then(function () { // done callback
$(".progress-bar").hide();
}, function () { // fail callback
$(".progress-bar").hide();
});
Whilst if you used .always(), you'd just need a single callback, because you always want to hide the progress bar, no matter if the $.Deferred was resolved or rejected:
$.get("/some/url").always(function () {
$(".progress-bar").hide();
});
Prior to jQuery 1.8: .always(fn) is equivalent to .then(fn, fn)
As of jQuery 1.8: .always(fn) is similar to .then(fn, fn) but it differs in what is returned (see http://api.jquery.com/deferred.then/ for details)
The big benefit of then (as of 1.8) is the capability to chain tasks explicitly because it returns a promise which will be resolved with the result of the callback(s)
Example from documentation:
var request = $.ajax( url, { dataType: "json" } ),
chained = request.then(function( data ) {
return $.ajax( url2, { data: { user: data.userId } } );
});
chained.done(function( data ) {
// data retrieved from url2 as provided by the first request
});

jQuery Deferred's, $.when() and the fail() callback arguments

I'm getting an unexpected result when using $.when() when one of the deferred operations does not succeed.
Take this JavaScript, which created 2 deferreds. The first one succeeds and the second one fails.
var f1 = function() {
return $.Deferred(function(dfd) {
dfd.resolve('123 from f1');
}).promise();
};
var f2 = function() {
return $.Deferred(function(dfd) {
dfd.reject('456 from f2');
}).promise();
};
$.when(f1(), f2())
.then(function(f1Val, f2Val) {
alert('success! f1, f2: ' + JSON.stringify([f1Val, f2Val]));
})
.fail(function(f1Val, f2Val) {
alert('fail! f1, f2: ' + JSON.stringify([f1Val, f2Val]));
});
Run it yourself: http://jsfiddle.net/r2d3j/2/
I get fail! f1, f2: ["456 from f2", null]
The problem is that in the .fail() callback the value passed with the f2() rejection, is being routed to the first argument, where i expect the f1Value. Which means that I don't really have a way of know which deferred object actually posted that reject(), and I also dont know which operation that failure data actually belongs to.
I would have expected that .fail() would get arguments null, '456 from f2' since the first deferred did not fail. Or am I just not doing deferreds right way here?
How do I know which deferreds failed, and which rejection arguments belong to which failed deferred if the argument order in the callback is not respected?
$.when() will execute the failed callback (2nd parameter passed to then()) immediately if any one of the parameters fails. It's by design. To quote the documentation:
http://api.jquery.com/jQuery.when/
In the multiple-Deferreds case where one of the Deferreds is rejected, jQuery.when immediately fires the failCallbacks for its master Deferred. Note that some of the Deferreds may still be unresolved at that point. If you need to perform additional processing for this case, such as canceling any unfinished ajax requests, you can keep references to the underlying jqXHR objects in a closure and inspect/cancel them in the failCallback.
There's actually no built-in way of getting a callback that waits untils all of them are finished regardless of their success/failure status.
So, I built a $.whenAll() for you :)
It always waits until all of them resolve, one way or the other:
http://jsfiddle.net/InfinitiesLoop/yQsYK/51/
$.whenAll(a, b, c)
.then( callbackUponAllResolvedOrRejected );
Internally, the "reject" and "fail" paths are handled by two totally separate queues, so it just doesn't work the way you expect.
In order to know which original Deferred failed from the "when()" group, you could have them pass themselves along with the ".reject()" call as part of an object literal or something.
I've faced this same problem, and I dealt with it by using the .always callback and inspecting my array of deferred objects. I had an unknown number of ajax calls, so I had to do the following:
// array of ajax deletes
var deletes = [];
$checkboxes.each(function () {
deletes.push(deleteFile(this));
});
$.when.apply($, deletes)
.always(function () {
// unfortunately .fail shortcircuits and returns the first fail,
// so we have to loop the deferred objects and see what happened.
$.each(deletes, function () {
this.done(function () {
console.log("done");
}).fail(function () {
console.log("fail");
});
});
});
The deleteFile method returns a promise, which has .done or .fail callbacks.
This allows you to take action after all deferreds have completed. In my case I'm going to show a delete file error summary.
I just tried this, and unfortunately I had to put a interval timer to check that they were all truly done after my $.each on the deferred objects. This seems odd and counterintuitive.
Still trying to understand these deferreds!
Very old question but now, to wait until all are resolved, you can use Promise.allSettled since $.ajax deals with standard promises.
The jqXHR objects returned by $.ajax() as of jQuery 1.5 implement the Promise interface, giving them all the properties, methods, and behavior of a Promise
Therefore you can use
Promise.allSettled([$.ajax(), $.ajax()])
.then((res) => {
if (res[0].status === 'fulfilled') {
console.log(res[0].value)
// do something
} else {
console.error('res1 unavailable')
}
if (res[1].status === 'fulfilled') {
console.log(res[1].value)
// do something
} else {
console.error('res2 unavailable')
}
})

Categories