$.when not working as I would expect - javascript

Please see the JavaScript below:
function LoadAjax(){
$.when(Possibles()) //Display Possibles first
.done(function () {
//alert('Possibles complete);
GetSQLTable();
LinkedUSNs();
})
}
I expect Possibles to complete and all the information to appear on the webpage before GetSQLTable and LinkedUSNs start. However, this does not happen. The information from GetSQLTable appears first. However, if I add an alert box (currently commented out in the code above), then it works. Why is this?
Possibles(), GetSQLTable() and LinkedUSNs() return HTML tables to the webpage via AJAX (JQuery).

Since you haven't posted the entire code. You might want to check the current state of the Deferred object in your promise (Possibles() function):
$.Deferred(function(deferred) {
// debug
console.log(deferred.state());
});
Or you can call resolved in your promise (which would call any doneCallbacks added by deferred.then() or deferred.done()):
$.Deferred(function(deferred) {
// dom ready?
$(deferred.resolve);
});

Related

Wait until all jQuery ajax calls are completed (done or rejected) [duplicate]

This question already has answers here:
$.Deferred: How to detect when every promise has been executed
(3 answers)
Closed 7 years ago.
I've looked through many similar questions but the proposed solutions do not work in all cases as expected. The following code works fine when all ajax calls are successfully done but if any of ajax calls happens to fail, then onComplete is immediately called:
var deferredArray = $('.preload').map(function() {
return $.get(this.href)
});
$.when.apply($, deferredArray).then(onComplete, onComplete);
So there can be two cases:
all deferred calls are successful, then onComplete is called afterwards - works fine;
some deferred call fails (returns HTTP 400 Bad request), then onComplete is called immediately not waiting for other deferred calls.
The second case represents my problem. It should always wait for all calls to complete regardless of the status before calling onComplete.
I use jQuery 1.7.1 as it's built into the framework. If the issue is due to the version, I can upgrade but I'd prefer to keep the current version.
You could try ajaxStop(). Allbeit not the most elegant solution.
$( document ).ajaxStop(function() {
// do some stuff now that all the ajax stuff has stopped
})
Also note:
If $.ajax() or $.ajaxSetup() is called with the global option set to false, the .ajaxStop() method will not fire.
I'm not sure if this outside of the scope of the types of solutions you're looking for, but I've recently been taking advantage of bluebird.js to wrap all my jquery ajax calls.
For example:
Promise.resolve($.get("http://www.google.com")).then(function() {});
What this allows me to do is then perform a Promise.all which will then wait for all the ajax calls to be complete. Each individual promise can pass or fail, but .then (or .spread) on the .all will only be called if they all succeed.
var aPass = function(){
return Promise.resolve($.get("/echo/json/"))
};
var aFail = function(){
return Promise.resolve($.get("/echo/jsonFake/")) // this will fail
};
var allPass = [aPass(), aPass(), aPass()];
var oneFails = [aPass(), aPass(), aFail()];
Promise.all(allPass).spread(function(a,b,c){
console.log("All Done!");
}).catch(function(){
console.log("NEVER FAILS!");
});;
Promise.all(oneFails).spread(function(a,b,c){
console.log("never goes in here");
}).catch(function(){
console.log("FAILED");
});
Here is a jsfiddle demonstrating this: http://jsfiddle.net/ys598t4s/2/

Understanding jQuery.Deferred in the context of jQuey.AJAX (again)

I concede that, despite hours of reading and attempting, I am fundamentally unable to grasp something about Deferred promises and asynchrony in general.
The goal on my end is real, real simple: send some data to the server, and react to the contents of the response conditionally.
The response will always be a JSON object with save and error keys:
{ "save": true, "error":false}
// or
{ "save" : false,
"error" : "The server has run off again; authorities have been notifed."}
I have tried dozens and dozens of variations from the jQuery API, from other stackexchange answers, from tutorials, etc.. The examples all seem concerned with local asynchronous activity. When I need is some ability to be made aware when the AJAX request has either finished and returned a response I can inspect and make decisions about, or else to know that it's failed. Below, I've used comments to explain what I think is happening so someone can show me where I'm failing.
I know this is a repost; I am, apprently, worse than on average at grasping this.
var postData = {"id":7, "answer":"Ever since I went to Disneyland..."};
/* when(), as I understand it, should fire an event to be
responded to by then() when it's contents have run their course */
var result = $.when(
/* here I believe I'm supposed to assert what must complete
before the when() event has fired and before any chained
functions are subsequently called */
/* this should return a jqXHR object to then(), which is,
I'd thought, a queue of functions to call, in order,
UPON COMPLETION of the asynchronous bit */
$.post("my/restful/url", postData))
.then( function() {
/* since "this" is the jqXHR object generated in the $.post()
call above, and since it's supposed to be completed by now,
it's data key should be populated by the server's response—right? */
return this.data;
});
// alas, it isn't
console.log(result.data);
// >> undefined
Most examples I can find discuss a timeout function; but this seems, as I understand, to be a failsafe put in place to arbitrarily decide when the asynchronous part is said to have failed, rather than a means of stalling for time so the request can complete. Indeed, if all we can do is just wait it out, how's that any different from a synchronous request?
I'll even take links to a new read-mes, tutorials, etc. if they cover the material in a different way, use something other than modified examples from the jQuery API, or otherwise help this drooling idiot through the asynchronous mirk; here's where I've been reading to date:
jQuery API: Deferred
JQuery Fundamentals
jQuery Deferreds promises asynchronous bliss (blog)
StackOverflow: timeout for function (jQuery)
Update
This is in response to #Kevin B below:
I tried this:
var moduleA = {
var moduleB = {
postData: {"id":7, "answer":"Ever since I went to Disneyland..."};
save: function() {
return $.post("path/to/service", postData, null, "JSON");
}
};
var result = this.moduleB.save();
result.done(function(resp) {
if (resp.saved == true) {
// never reached before completion
console.log("yahoo");
} else {
console.log("Error: " + resp.error);
// >> undefined
}
});
}
You are over-complicating your code. You cannot get the data to outside of the callback, no matter how many deferred/promises you create/use (your sample creates 3 different deferred objects!)
Use the done callback.
var postData = {"id":7, "answer":"Ever since I went to Disneyland..."};
$.post("my/restful/url", postData).done(function (result) {
console.log(result.save, result.error);
});
You seem to have a misunderstanding of both asynchronous requests, the Promise pattern, and Javascripts mechanism of passing functions as an argument.
To understand what's really happening in your code I suggest you use a debugger and set some breakpoints in the code. Or, alternatively, add some console.logs in your code. This way you can see the flow of the program and might understand it better. Also be sure to log the arguments of the function you pass as an argument in the then()-method, so you understand what is passed.
ok you got it half right. the problem is that when you execute the console.log the promised is not yet fulfilled the asynchronous nature of the promises allows the code to execute before that ajax operation is done. also result is a deferred not a value, you need to handle your promised with .done instead of .then if you wish to return a value otherwise you'll continue passing promises.
so that said
var result={};
$.when(
$.post("my/restful/url", postData))
.done( function(data) {
result.data=data;
});
// here result is an object and data is a undefined since the promised has no yet been resolve.
console.log(result.data);

File APIs Javascript FileReader onload

I am using File APIs with Javascript.
I need to wait for the completation of onload method, how can I do it?
reader.onload = function (e) {
contents = reader.result;
var addAttchCallBack = loadRequestExecutor();
addAttchCallBack.done(function (data) {
alert("ok");
})
};
alert("Ko");
I see always before "Ko"
N.B: the function loadRequestExecutor() correctly returns a promise obj.
Thanks,Nk
You really need to study up on Async behavior and callbacks, then take on understanding promises, as your examples are an odd combination of callbacks and promises, but, to try and explain what is going on in basic terms:
Example 1:
You always seeing KO first, because the first example does this:
Assign a function to a property that will be called back later
Show a KO alert
At some time later the file loads, starts the executor, which on complete (if it ever does) alerts OK
so, basically your onload function will only get called after the file loads (asynchronously), so the alert on the next line gets executed immediately.
Example 2:
You second example, in a comment, is this:
$.when(reader.onload = function (e) {
contents = reader.result;
return loadRequestExecutor();
}).done(function (a) {
alert("ok");
});
alert("KO");
Which translates to:
Assign a function to a property that will be called back later
Pass that same function to when but do not execute it!!!
Show a KO alert
At some time later when the file loads, return the loadRequestExecutor() to the filereader!!!
The end result is not returning the promise to the wait, which is what you probably meant, so it will never work as expected.
Suggestion:
I do not know the plugins that well, but you appear to need to record a promise relating to the load request executor, if that is what you want to wait for.
// Create the loadRequestExecutor and record the promise
var addAttchCallBack = loadRequestExecutor();
// Setup the onload callback
reader.onload = function (e) {
contents = reader.result;
alert("ok - file load is done");
};
// Listen for the loadRequestExecutor to complete
addAttchCallBack.done(function (data) {
alert("Ko - loadRequestExecutor is done");
})
alert("I am just an alert that will happen first, as everything above is asynchronous!");
Your overall aim is not clear from the question, so this answer mainly focuses on exampling why your two attempts do not work as you expected.

Chaining jQuery promises/deferreds

I have a process where I have to send an ajax request to the server, but need to stop a scheduler before the ajax request begins, then restart the scheduler when the request is done.
I have got this working using the following code:
scheduler.stop()
.done(function () {
setQuestionStatus().done(scheduler.start);
});
But it seems that there should be a simpler way to write this, such as:
scheduler.stop().then(setQuestionStatus).then(scheduler.start);
My problem is that when written this way, setQuestionStatus and scheduler.start are both called as soon as scheduler.stop has resolved, rather than after each item in the chain has resolved.
Can anyone tell me what I'm doing wrong in the second example?
For your information, both scheduler.stop and setQuestionStatus return a promise using the pattern:
var setQuestionStatus = function(){
return $.Deferred(function (def) {
// Do stuff
def.resolve();
}).promise();
}
scheduler.stop().then(setQuestionStatus).then(scheduler.start);
My problem is that when written this way, setQuestionStatus and scheduler.start are both called as soon as scheduler.stop has resolved, rather than after each item in the chain has resolved.
That's ugly non-standard behavior found in earlier versions of jQuery. Either update your copy to 1.8+ for using then, or use the pipe method instead.

Syntax for javascript object implementing an AJAX GET and custom event

I've got a couple of questions about this small snippett adapted from a tutorial I found here.
var loader = (function ($, host) {
return {
loadTemplate: function (path) {
var tmplLoader = $.get(path)
.success(function (result) {
$("body").append(result);
})
.error(function (result) {
alert("Error Loading Template");
}) // --> (1) SEMICOLON?
// (2) How does this wire up an event to the previous
// jQuery AJAX GET? Didn't it already happen?
tmplLoader.complete(function () {
$(host).trigger("TemplateLoaded", [path]);
});
}
};
})(jQuery, document);
Is there supposed to be a semicolon there?
It seems like the AJAX GET is happening and then an event is getting wired to it - what am I missing here?
Is there supposed to be a semicolon there?
It's optional, but recommended.
It seems like the AJAX GET is happening and then an event is getting wired to it - what am I missing here?
AJAX is asynchronous, so it's very unlikely the request will be already completed right after sending it. So, there's time to add another callback. And even if there weren't, it would work anyway, since jQuery implements those callbacks with promises. See example here.
With javascript, and ajax in particular it is important to understand how the browser goes about executing your code. When you make the request for remote data via an ajax GET, the rest of your code is still executing. Imagine if as soon as you made a request for some JSON to a busy server, lets say it takes a couple seconds, and everything on your page stops working during that time period. It would be very difficult to write code that wasn't difficult for the user to interact with. Luckily ajax is async, meaning it makes the request and an carries on as usual until the complete event (or equivalent) is fired. This is what executes your code pertinent to the data you just received. So when you specify that callback at the bottom of your snippit, you are telling the browser, "go do your thing for now but when you hear back from the server, do all of these things".
Oh yeah, and semicolons are optional, but as a best practice, most people use them.
They are assigning the $.get to a variable and then adding a complete handler to it.
It's the same as doing this:
$.get('/path'), function(){
//success callback
}).error(function(e){
//errors
}).complete(function(){
//always run
});
Just an unusual way of doing it.

Categories

Resources