jquery $.done is executed immedietely - javascript

$.when(fetchingOutcomeTab()).done(alert("1"));
function fetchingOutcomeTab() {
var dfd = $.Deferred();
setTimeout(function() {
dfd.resolve('qqqqq');
}, 2000);
return dfd.promise();
}
I am trying to make alert("1") triggered waiting until fetchingOutcomeTab function done, but everytime it will triggered immedietely, please help.

You need to pass a function to .done(). You're calling alert() immediately and passing its return value.
$.when(fetchingOutcomeTab()).done(() => alert("1"));

Since your function returns a deferred object, you can chain done() directly to the function call. Also, done() expects a parameter that's a "function or array of functions".
fetchingOutcomeTab().done(function() {
console.log('resolved.');
});
function fetchingOutcomeTab() {
console.log('Deferring...');
var dfd = $.Deferred();
setTimeout(function() {
dfd.resolve('qqqqq');
}, 2000);
return dfd;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Related

Using java script promises for calling function once

var dataPromise= $q.defer();
function getDataPromise(){
return dataPromise.promise;
}
(function getData(){
setTimeOut(
function(){
myPromise.resolve("data");
}
,1000);
})();
getDataPromise().then(function(){alert("use old data");});
In this code "dataPromise" defined out of "getData" function scope, therefor new promise won't be created on each "getData" invocation.
"getData" will invoce once and "dataPromise" will hold the first invoke data, and won't be update.
I want to understand if this is promise anty-pattern? if so - what is the correct way to call async function once?
Here's how I would write it:
const dataPromise = $q(function(resolve) {
setTimeOut(function() {
resolve("data");
}, 1000);
});
function getDataPromise() {
return dataPromise;
}
getDataPromise().then(function(){alert("use old data");});

How to use $q.deffer to chain ajax requests?

I need to do this: browser have to make N requests to the server, requests mustn't be async, next requests are starting after previous requests will stop.
I can write some function A with for i < N i++ and calling this function A again recursively to do this, but it is not beautifull at all. Also, this called callback hell. I want some more beautifull solution.
I found deffered objects. Some says, it can help me to escape callback hell. I want something like this. setTimeout there is imitate one async request:
function foo1(some) {
debugger;
setTimeout(function foo1async() {
debugger;
deffered.resolve();
}, 500);
return deffered.promise;
}
function foo2(some) {
debugger;
setTimeout(function foo2async() {
debugger;
deffered.reject();
}, 500);
return deffered.promise;
}
function foo3() {
debugger;
setTimeout(function foo3async() {
debugger;
deffered.resolve();
}, 500);
return deffered.promise;
}
var deffered;
function doChain() {
debugger;
deffered = $q.defer();
var promise = deffered.promise;
promise.then(foo1);
promise.then(foo2);
promise.then(foo3);
promise["finally"](function () {
debugger;
});
deffered.resolve();
}
I expect foo1 to be called, then foo1async will be called and resolve deffered object.
foo2 must be called, then foo2async is called.
3.Now I expect, that foo3 wouldn't start, because deffered is rejected in foo2async. After that I expect foo in finally section called.
Actually, I have this:
foo1, foo2 and foo3 are called. Then foo in finally section called. Then foo1async, foo2async and foo3async funtions are called.
How I can get what I am expecting?
Actually, I will have something like this:
for(var i = 0; i < N; i++) {
(function (iter) {
promise.then(function () {
foo(iter);
});
})(i);
}
You got a few things wrong here.
First, you use a deferred to convert a callback-based async function into a promise-based - but each one needs its own deferred.promise and thus its own deferred. Actually, I prefer to use the $q constructor instead:
function fooN(input){
return $q(function(resolve, reject){
setTimeout(function(){
resolve(input + "; some more data");
}, 500);
});
}
(you could use var deferred = $q.defer() as well)
fooN now returns a promise, so you don't need to use $q.defer() anymore.
In fact, if the async function already was promise-based, like $timeout or $http, then you wouldn't have needed a deferred at all, for ex:
function fooN(input){
return $timeout(function(){
return input + "; some more data";
}, 500);
})
So, let's assume that foo1, foo2 and foo3 are implemented like fooN - all returning promises.
To make the calls sequential, you would need to chain promises - not to attach multiple handlers to the some root promise.
I'll break it down for you:
function doChain(){
var foo1Promise = foo1();
var foo2AfterFoo1Promise = foo1Promise.then(foo2);
var foo3AfterFoo2Promise = foo2AfterFoo1Promise.then(foo3);
var promise = foo3AfterFoo2Promise.then(function(finalData){
return doSomeProcessing(finalData); // if needed
});
promise.catch(function(error){
// "rethrow", if can't handle
return $q.reject({msg: "Some error occurred"});
})
return promise;
}
Or, the same, more concise:
function doChain(p){
return foo1(p)
.then(foo2)
.then(foo3)
.then(function(finalData){
return doSomeProcessing(finalData);
})
.catch(function(error){
return $q.reject({msg: "Some error occurred"});
});
}
A "promised" return value of each function is an input to the next chained function.
You can use $q.all method. For instance:
var promises = [promise1, promise2, ...];
$q.all(promises).then(function () {
// do something
});
What happens now is that all foo* promises depend on the single promise; when it gets resolved all are triggered. In ASCII art the dependencies are:
┎ foo1
promise ╁ foo2
┖ foo3
What you want is:
function doChain() {
foo1()
.then(foo2)
.then(foo3)
;
}
No need for the extra promise. No callback hell either!

Chaining ajax requests with jQuery's deferred

I have a web app which must call the server multiple times. So far, I had a long nested callback chain; but I would like to use jQuery's when,then etc. functionality. However, I can't seem to get stuff running again after using a then.
$
.when ($.get('pages/run-tool.html'))
.then (function (args)
{
// This works fine
alert(args);
$('#content').replaceWith (args);
$('#progress-bar').progressbar ({value: 0});
})
.then ($.get('pages/test.html'))
.done (function(args)
{
// This prints the same as the last call
alert (args);
});
What am I doing wrong? I guess its some scoping issue, as I can see the second get call being executed. Using two different args variables does not help as the argument passed to the done function is still the first get request.
As an update:
With modern jquery (1.8+) you don't need the preliminary when because get returns a Deferred Promise.
Also, pipe is deprecated. Use then instead. Just be sure to return the result of the new get which becomes the Promise attached to by subsequent then/*done*/fail calls.
So:
$.get('pages/run-tool.html')
.then (function (args) { // this will run if the above .get succeeds
// This works fine
alert(args);
$('#content').replaceWith (args);
$('#progress-bar').progressbar ({value: 0});
})
.then (function() { // this will run after the above then-handler (assuming it ran)
return $.get('pages/test.html'); // the return value creates a new Deferred object
})
.done (function(args) { // this will run after the second .get succeeds (assuming it ran)
alert (args);
});
All three callbacks (the two with then and the one with done) are applied to the same request – the original when call. This is because then returns the same Deferred object, rather than a new one, so that you can add multiple event handlers.
You need to use pipe instead.
$
.when ($.get('pages/run-tool.html'))
.then (function (args)
{
// This works fine
alert(args);
$('#content').replaceWith (args);
$('#progress-bar').progressbar ({value: 0});
})
.pipe (function() {
return $.get('pages/test.html'); // the return value creates a new Deferred object
})
.done (function(args)
{
alert (args);
});
Here is an wonderfully simple and highly effective AJAX chaining / queue plugin. It will execute you ajax methods in sequence one after each other.
It works by accepting an array of methods and then executing them in sequence. It wont execute the next method whilst waiting for a response.
//--- THIS PART IS YOUR CODE -----------------------
$(document).ready(function () {
var AjaxQ = [];
AjaxQ[0] = function () { AjaxMethod1(); }
AjaxQ[1] = function () { AjaxMethod2(); }
AjaxQ[3] = function () { AjaxMethod3(); }
//Execute methods in sequence
$(document).sc_ExecuteAjaxQ({ fx: AjaxQ });
});
//--- THIS PART IS THE AJAX PLUGIN -------------------
$.fn.sc_ExecuteAjaxQ = function (options) {
//? Executes a series of AJAX methods in dequence
var options = $.extend({
fx: [] //function1 () { }, function2 () { }, function3 () { }
}, options);
if (options.fx.length > 0) {
var i = 0;
$(this).unbind('ajaxComplete');
$(this).ajaxComplete(function () {
i++;
if (i < options.fx.length && (typeof options.fx[i] == "function")) { options.fx[i](); }
else { $(this).unbind('ajaxComplete'); }
});
//Execute first item in queue
if (typeof options.fx[i] == "function") { options.fx[i](); }
else { $(this).unbind('ajaxComplete'); }
}
}
The answer cdr gave, which has the highest vote at the moment, is not right.
When you have functions a, b, c each returns a $.Deferred() object, and chains the functions like the following:
a().then(b).then(c)
Both b and c will run once the promise returned from a is resolved. Since both then() functions are tied to the promise of a, this works similiar to other Jquery chaining such as:
$('#id').html("<div>hello</div>").css({display:"block"})
where both html() and css() function are called on the object returned from $('#id');
So to make a, b, c run after the promise returned from the previous function is resolved, you need to do this:
a().then(function(){
b().then(c)
});
Here the call of function c is tied to the promise returned from function b.
You can test this using the following code:
function a() {
var promise = $.Deferred();
setTimeout(function() {
promise.resolve();
console.log("a");
}, 1000);
return promise;
}
function b() {
console.log("running b");
var promise = $.Deferred();
setTimeout(function () {
promise.resolve();
console.log("b");
}, 500);
return promise;
}
function c() {
console.log("running c");
var promise = $.Deferred();
setTimeout(function () {
promise.resolve();
console.log("c");
}, 1500);
return promise;
}
a().then(b).then(c);
a().then(function(){
b().then(c)
});
Change the promise in function b() from resolve() to reject() and you will see the difference.
<script type="text/javascript">
var promise1 = function () {
return new
$.Deferred(function (def) {
setTimeout(function () {
console.log("1");
def.resolve();
}, 3000);
}).promise();
};
var promise2 = function () {
return new
$.Deferred(function (def) {
setTimeout(function () {
console.log("2");
def.resolve();
}, 2000);
}).promise();
};
var promise3 = function () {
return new
$.Deferred(function (def) {
setTimeout(function () {
console.log("3");
def.resolve();
}, 1000);
}).promise();
};
var firstCall = function () {
console.log("firstCall");
$.when(promise1())
.then(function () { secondCall(); });
};
var secondCall = function () {
console.log("secondCall")
$.when(promise2()).then(function () { thirdCall(); });
};
var thirdCall = function () {
console.log("thirdCall")
$.when(promise3()).then(function () { console.log("done"); });
};
$(document).ready(function () {
firstCall();
});
</script>
I thought I would leave this little exercise here for anyone who may find it useful, we build an array of requests and when they are completed, we can fire a callback function:
var urls = [{
url: 'url1',
data: 'foo'
}, {
url: 'url2',
data: 'foo'
}, {
url: 'url3',
data: 'foo'
}, {
url: 'url4',
data: 'foo'
}];
var requests = [];
var callback = function (result) {
console.log('done!');
};
var ajaxFunction = function () {
for (var request, i = -1; request = urls[++i];) {
requests.push($.ajax({
url: request.url,
success: function (response) {
console.log('success', response);
}
}));
}
};
// using $.when.apply() we can execute a function when all the requests
// in the array have completed
$.when.apply(new ajaxFunction(), requests).done(function (result) {
callback(result)
});
My way is to apply callback function:
A(function(){
B(function(){
C()})});
where A, B can be written as
function A(callback)
$.ajax{
...
success: function(result){
...
if (callback) callback();
}
}

javascript - setTimeout return

How can I use setTimeout if I want to return a value
$.each(pCodes, function(index, pCode) {
setTimeout(func(parm1), 2000);
});
function func(in)
{
var value = 999;
return value;
}
First of all, your call to setTimeout is wrong. You are calling the function func and then using the result in the setTimeout method. Your code is equivalent to:
$.each(pCodes, function(index, pCode) {
var temp = func(parm1);
setTimeout(temp, 2000);
});
As func returns 999, you will be doing setTimeout(999, 2000), which of course doesn't make sense. To call a function that takes a parameter from setTimeout you need a function that makes that function call:
$.each(pCodes, function(index, pCode) {
setTimeout(function() { func(parm1); }, 2000);
});
To handle the return value from func is a bit more complicated. As it's called later on, you have to handle the return value later on. Usually that is done with a callback method that is called when the return value is available:
var callback = function(value) {
// Here you can use the value.
};
$.each(pCodes, function(index, pCode) {
setTimeout(function() { func(parm1, callback); }, 2000);
});
function func(in, callback) {
var value = 999;
callback(value);
}
First of all, make sure you pass to setTimeout a function, in your example you passed undefined to it, as you func(param1) executes func directly. What you want is something like this:
setTimeout(function() { func(parm1); }, 2000);
And for 'returning' the value: Use some kind of callback function that is executed with the value when timeout expired. Like so:
function callback(value) {
// doSomethingWithNewValue
}
$.each(pCodes, function(index, pCode) {
setTimeout(function() { func(parm1, callback); }, 2000);
});
function func(in, callback)
{
var value = 999;
callback(value);
}
This is the general pattern used in such scenario (see event driven programming).
change it to :
var defValue;
$.each(pCodes, function(index, pCode) {
setTimeout(function(){defValue=func(parm1)}, 2000);
});
this way you can use the defValue in your function to access the returned value
It's pretty ugly, but you can use output parameters, since js objects are pass by reference:
function a() {
var param1 = 42;
var result = {};
b(param1, result);
}
function b(val, output) {
something();
output.returned = 4;
}
Or, you can use a callback (the better option):
function a() {
var param1 = 42;
b(param1, function (newVal) {
something();
});
}
function b(val, callback) {
//something
callback(4);
}
By the way, your call to setTimeout is wrong. setTimeout receives a function as a first parameter, and a delay as a second - the first argument is still seen as regular javascript code, so it evaluates it, so your setTimeout call turns out to be like this:
setTimeout(999, 2000);
Since you're returning 999 from the function.
However, setTimeout can also receive a list of arguments after the second parameter, so it can be turned into this:
setTimeout(func, 2000, param1);

Call a function after previous function is complete

I have the following JavaScript code:
$('a.button').click(function(){
if (condition == 'true'){
function1(someVariable);
function2(someOtherVariable);
}
else {
doThis(someVariable);
}
});
How can I ensure that function2 is called only after function1 has completed?
Specify an anonymous callback, and make function1 accept it:
$('a.button').click(function(){
if (condition == 'true'){
function1(someVariable, function() {
function2(someOtherVariable);
});
}
else {
doThis(someVariable);
}
});
function function1(param, callback) {
...do stuff
callback();
}
If you're using jQuery 1.5 you can use the new Deferreds pattern:
$('a.button').click(function(){
if(condition == 'true'){
$.when(function1()).then(function2());
}
else {
doThis(someVariable);
}
});
Edit: Updated blog link:
Rebecca Murphy had a great write-up on this here: http://rmurphey.com/blog/2010/12/25/deferreds-coming-to-jquery/
Try this :
function method1(){
// some code
}
function method2(){
// some code
}
$.ajax({
url:method1(),
success:function(){
method2();
}
})
This answer uses promises, a JavaScript feature of the ECMAScript 6 standard. If your target platform does not support promises, polyfill it with PromiseJs.
Promises are a new (and a lot better) way to handle asynchronous operations in JavaScript:
$('a.button').click(function(){
if (condition == 'true'){
function1(someVariable).then(function() {
//this function is executed after function1
function2(someOtherVariable);
});
}
else {
doThis(someVariable);
}
});
function function1(param, callback) {
return new Promise(function (fulfill, reject){
//do stuff
fulfill(result); //if the action succeeded
reject(error); //if the action did not succeed
});
}
This may seem like a significant overhead for this simple example, but for more complex code it is far better than using callbacks. You can easily chain multiple asynchronous calls using multiple then statements:
function1(someVariable).then(function() {
function2(someOtherVariable);
}).then(function() {
function3();
});
You can also wrap jQuery deferrds easily (which are returned from $.ajax calls):
Promise.resolve($.ajax(...params...)).then(function(result) {
//whatever you want to do after the request
});
As #charlietfl noted, the jqXHR object returned by $.ajax() implements the Promise interface. So it is not actually necessary to wrap it in a Promise, it can be used directly:
$.ajax(...params...).then(function(result) {
//whatever you want to do after the request
});
Or you can trigger a custom event when one function completes, then bind it to the document:
function a() {
// first function code here
$(document).trigger('function_a_complete');
}
function b() {
// second function code here
}
$(document).bind('function_a_complete', b);
Using this method, function 'b' can only execute AFTER function 'a', as the trigger only exists when function a is finished executing.
you can do it like this
$.when(funtion1()).then(function(){
funtion2();
})
This depends on what function1 is doing.
If function1 is doing some simple synchrounous javascript, like updating a div value or something, then function2 will fire after function1 has completed.
If function1 is making an asynchronous call, such as an AJAX call, you will need to create a "callback" method (most ajax API's have a callback function parameter). Then call function2 in the callback. eg:
function1()
{
new AjaxCall(ajaxOptions, MyCallback);
}
function MyCallback(result)
{
function2(result);
}
If method 1 has to be executed after method 2, 3, 4. The following code snippet can be the solution for this using Deferred object in JavaScript.
function method1(){
var dfd = new $.Deferred();
setTimeout(function(){
console.log("Inside Method - 1");
method2(dfd);
}, 5000);
return dfd.promise();
}
function method2(dfd){
setTimeout(function(){
console.log("Inside Method - 2");
method3(dfd);
}, 3000);
}
function method3(dfd){
setTimeout(function(){
console.log("Inside Method - 3");
dfd.resolve();
}, 3000);
}
function method4(){
console.log("Inside Method - 4");
}
var call = method1();
$.when(call).then(function(cb){
method4();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
If function1 is some sync function that you want to turn into an async one because it takes some time to complete, and you have no control over it to add a callback :
function function1 (someVariable) {
var date = Date.now ();
while (Date.now () - date < 2000); // function1 takes some time to complete
console.log (someVariable);
}
function function2 (someVariable) {
console.log (someVariable);
}
function onClick () {
window.setTimeout (() => { function1 ("This is function1"); }, 0);
window.setTimeout (() => { function2 ("This is function2"); }, 0);
console.log ("Click handled"); // To show that the function will return before both functions are executed
}
onClick ();
The output will be :
Click handled
...and after 2 seconds :
This is function 1
This is function 2
This works because calling window.setTimeout () will add a task to the JS runtine task loop, which is what an async call makes, and because the basic principle of "run-to-completion" of the JS runtime ensures that onClick () is never interrupted before it ends.
Notice that this as funny as it makes the code difficult to understand...

Categories