My problem is b() executing lastly, but it should be 2nd in the order. I want to call a JSON api on every click on a button (and always send new api call), but it should remove the last api message from the div:
$(document).ready(function() {
function test() {
function a() {
$("#message-quote, #message-person").empty();
console.log('p1');
};
function b() {
console.log('p2 - before getJSON');
$.getJSON("http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&callback=", function(a) {
$("#message-quote").append(a[0].content)
$("#message-person").append("<p>— " + a[0].title + "</p>")
console.log('p2 - in getJSON');
});
};
function c() {
$("body, .button, .quote-icons a").css("background-color", "red");
$(".quote-text").css("color", "red");
console.log('p3');
};
var d = $.Deferred(),
p = d.promise();
p.then(a()).then(b()).then(c());
d.resolve();
};
$("#getMessage").on("click", function() {
test();
});
});
The order I got is:
"p1"
"p2 - before getJSON"
"p3"
"p2 - in getJSON"
Your not waiting for the return of b(), you need to chain the promises due to it calling Asynchronously.
if you return a promise out of b(), it should then wait for result of getJSON to be return before it continues.
also, your functions are executing straight away, .then(callback) needs to take a function it can execute later, where your executing a function straight away instead
function b() {
return $.getJSON("http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&callback=", function(a) {
$("#message-quote").append(a[0].content)
$("#message-person").append("<p>— " + a[0].title + "</p>")
console.log('p2');
// resolve the promise, the call has been completed
});
};
var d = $.Deferred(),
p = d.promise();
p.then(a)
.then(b)
//the context of .then will now be the promise out of b()
.then(c);
d.resolve();
Note : Promises will need to also be returned form each other method.
EDIT: as Rocket pointed out, jQuery Ajax calls implement the promise methods
working example : https://jsfiddle.net/rsfxpg38/4/
you can see an example of it from this post :
How do I chain a sequence of deferred functions in jQuery 1.8.x?
Related
function firstFunction(_callback){
// do some asynchronous work
// and when the asynchronous stuff is complete
_callback();
}
function secondFunction(){
// call first function and pass in a callback function which
// first function runs when it has completed
firstFunction(function() {
console.log('huzzah, I\'m done!');
});
}
This is an example from this site, I would like help understanding it.
If I have a function that sums 2 number and the other returns it. So:
var z = 0;
function firstf (x, y, callback){
z = x + y;
callback();
}
function secondf () {
console.log(z);
}
I dont get how this works? How do I make it so that secondf waits until firstf is done using callbacks?
After define 2 function, you call:
firstf(2,3,secondf);
Follow : z=2+3 then call function callback. And now, function callback ~ secondf :
z=2+3 ;
secondf();
If you want to the second block to wait until the first block is done. Then using callback makes no sense.
Because the main concept of callback is to provide an asynchronous platform.
A callback is a function call at the completion of a given task, hence prevents any blocking which may might occur if the first block takes long time to load data.
So, if you want both the blocks to work asynchronously the use callback, and to achieve what you are asking simply call the second function after the task of block one is done.
For better understanding go through this link,
https://docs.nodejitsu.com/articles/getting-started/control-flow/what-are-callbacks/
Best of luck!
You can use "promise" concept to ensure that the secondf waits until firstf is done:
function firstf(x,y){
return new Promise(
function (resolve, reject) {
resolve(x+y);
});
}
function secondf(){
firstf(x,y).then ( function (result){
console.log(result);
});
}
By re-ordering your code:
edit Made code async for demo purposes
var z = 0;
function firstf(x, y, callback) {
console.log("Inside firstf");
z = x + y;
console.log("Will call callback in 1 second");
// Lets make this function async.
setTimeout(function() {
console.log("Calling callback");
callback();
}, 1000);
}
function secondf() {
console.log("Inside secondf");
console.log(z);
console.log("Leaving secondf");
}
firstf(1, 2, secondf);
I have to call 3 functions with AJAX requests before one of the functions can be finished. All functions needs the same data, so I want to start the AJAX request only once. I think that I need a functionality to call 2 of the 3 functions to wait and provide the data at the end. Maybe the problem is that I am new to jQuery Deferred and dont find some basic stuff? Thanks for help!
Because my script is to complex as example so I created this demo: (I hope it is self explanatory)
<script>
var requestRunning = false;
//do some ajax request etc...
function doSomething() {
return {
doIt: function (test, startDelay) {
var dfd = $.Deferred();
setTimeout(function () {
if (requestRunning == false) {
console.log("starting ajax call:", test);
requestRunning = true;
//Fake ajax call
setTimeout(function () {
dfd.resolve(test);
// Todo: A done; provide data to waiting B and C.
}, 500);
}
else {
console.log("ajax call allready running, waiting...", test);
}
}, startDelay);
return dfd.promise();
}
}
}
// Fake delay for function calls in really short time
var master = doSomething();
var a = master.doIt("a", 10);
var b = master.doIt("b", 15);
var c = master.doIt("c", 12);
// Do some stuff with the received data...
a.done(function myfunction(result) {
console.log(result + " done");
});
b.done(function myfunction(result) {
console.log(result + " done");
});
c.done(function myfunction(result) {
console.log(result + " done");
});
</script>
I'm not entirely sure what you are trying to do, but if what you want to do is to start three ajax calls at once and then know when all of them are done, since jQuery ajax calls already return a promise, you can use that promise and $.when() like this:
var p1 = $.ajax(...);
var p2 = $.ajax(...);
var p3 = $.ajax(...);
$.when(p1, p2, p3).then(function(r1, r2, r3) {
// results of the three ajax calls in r1[0], r2[0] and r3[0]
});
Or, you can even do it without the intermediate variables:
$.when(
$.ajax(...),
$.ajax(...),
$.ajax(...)
).then(function(r1, r2, r3) {
// results of the three ajax calls in r1[0], r2[0] and r3[0]
});
If you are calling functions that themselves do ajax calls, then you can just return the ajax promise from those functions and use the function call with the structure above:
function doSomethingAjax() {
// some code
return $.ajax(...).then(...);
}
$.when(
doSomethingAjax1(...),
doSomethingAjax2(...),
doSomethingAjax3(...)
).then(function(r1, r2, r3) {
// results of the three ajax calls in r1[0], r2[0] and r3[0]
});
I'm trying to understand Promise. But here I'm confused.
I want to create a test function that will print 3000 after 3 second, then print 2000 after 2 second, then print 1000 after 1 second. Here is my code:
'use strict';
var Q = require('q');
function delayConsole(timeOut) {
var defer = Q.defer();
setTimeout(function(){
console.log(timeOut);
defer.resolve(2000);
},timeOut);
return defer.promise;
}
// This works
delayConsole(3000).then(function(){
return delayConsole(2000);
}).then(function(){
return delayConsole(1000);
});
// This doesn't work. Why?
delayConsole(3000).then(delayConsole(2000)).then(delayConsole(1000));
There, you call the function delayConsole immediately :
.then(delayConsole(2000))
That is : you don't pass the function but the result of the function call, you don't wait for the promises to be chained.
When you do
then(function(){
return delayConsole(2000);
})
then you pass a function, not the result of that function call. The function can be called when the previous element in the promise chain is solved.
I just thought I'd share that you can make this construction work which is sometimes easier to use:
promise.then(delayConsole(3000)).then(delayConsole(2000)).then(delayConsole(1000));
by changing delayConsole() to this:
function delayConsole(timeOut) {
return function() {
var defer = Q.defer();
setTimeout(function(){
console.log(timeOut);
defer.resolve(2000);
},timeOut);
return defer.promise;
}
}
This way, calling delayConsole() just captures the timeout argument and returns a function that can be called later by the promise .then handler. So, you are still passing a function reference to the .then() handler which lets the promise engine call the internal function sometime later rather than execute it now.
I want function A to finish execution and only after that function B should start executing. When I call function A and then function B, it seems both are executing simultaneously. And after function B completes, I want to call a third function update_dropdown().
My code looks like this:
function A {
for (var i = 0; i < 5; i++) {
var promise = $.get(url+i);
$.when(promise).then(function () {
$.post(url);
});
}
}
function B {
var x = $.get(url);
var promise = $.post(url+x);
$.when(promise0).then(function () {
update_dropdown();
});
}
Please can you tell me how I can make these 3 function calls happen sequentially.
OK, it's getting a little bit clearer what you actually want (based on your recent comments to address clarifying questions) though there are still at least two options open.
For an operation like this, you probably want to take advantage of a number of promise features:
jQuery's Ajax calls already return a promise so you can just use those directly
To serialize operations, you can just chain multiple promise operations together
To make async operations serialize properly, you can return a promise from a .then() handler and the master promise will resolve only when all the chained promises have resolved (kind of a built-in $.when() without having to explicitly call $.when()).
You can chain as many operations together as you want and the master promise will tell you when they are all done.
If you return promises from both A() and B(), then the callers of those functions can monitor when they are done with promise methods which then lets you chain A().then(B) to sequence those two.
When you sequence operations with chaining, the prior methods resolve data is passed to the next .then() handler function in the chain as the first argument to the .then() handler function so if you need the prior data for the next operation, it is right there to use.
So, with all those capabilities, it's just a matter of putting the right scaffolding around the code to implement the exact sequencing you want. Here are two different options:
Option 1: If you want to serialize everything in A() so that all 10 requests happen in serial fashion (the next one proceeds only when the prior one is done), then it could look like this:
// serialize all requests
function A() {
var p = $.get(url).then(function(data) {return $.post(url)});
for (var i = 1; i < 5; i++) {
// chain four more pairs of requests onto the original promise
p = p.then(function() {return $.get(url)})
.then(function(data) {return $.post(url)});
}
// return the promise so callers can monitor when A() is done
return p;
}
function B() {
// sequence these three operations one after the other
return ($.get(url)
.then(function(data) {return $.post(url + x)})
.then(update_dropdown)
);
}
// run them both, one after the other
A().then(B);
Option 2: If you want the 5 pairs of requests in A() to run in parallel, with only the last part of A() waiting until the 5 pairs of requests are done, then it could look like this:
// parallelize pairs of requests
function A() {
var promises = [];
for (var i = 0; i < 5; i++) {
// execute 5 pairs of requests where each pair is serialized in itself
promises.push($.get(url).then(function(data) {return $.post(url)}));
}
// return a promise that resolves only when all the other promises are done
return $.when.apply($, promises);
}
function B() {
// sequence these three operations one after the other
return ($.get(url)
.then(function(data) {return $.post(url + x)})
.then(update_dropdown)
);
}
// run them both, one after the other
A().then(B);
These use the concept that if you return a promise from a .then() handler function, then it will chain multiple async operations together and the master promise is only resolved when all the chained operations are resolved. This is very powerful for sequencing multiple ajax operations and you can even do it for operations in a loop like you have.
Something like this should work
function A {
var xhr = [];
for (var i = 0; i < 5; i++) {
xhr.push( $.get(url) );
}
$.when.apply($, xhr).then(B);
}
function B {
$.get(url).done(function(x) {
$.post(url + x).done(update_dropdown);
});
}
Note the use of an array to keep the promises in, then using $.when with apply() to fire a callback when all the ajax requests in the loop has finished.
Assumptions assumptions ...
Let's assume that :
the url for every get is the same as that for its corresponding post
the urls for each get-post pair should vary
the five get-post pairs in A can occur in parallel and we are not interested in the returned data
First, a utility function :
function getThenPost(url, appendToURL) {
return $.get(url).then(function(x) {
return (appendToURL) ? $.post(url + x) : $.post(url);
});
}
then A and B, both of which call the utility :
function A(urls) {
return $.when.apply(null, urls.map(function(url) {
return getThenPost(url, false);
}));
}
function B(url) {
return getThenPost(url, true);
}
and finally an expression that calls A and B :
A(['/path/0', '/path/1', '/path/2', '/path/3', '/path/4']).then(function() {
B('/path/5');
}).then(update_dropdown);
It should be reasonably simple to adjust this code if assumptions 1 and 2 are incorrect.
If assumption 3 is incorrect then A will require more extensive modification.
We can call our choice function in our way using jquery Deferred Object.
It is very simple let see successfully run example:
<body>
<script
src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript">
// I want to call function in order of f1,f2,f3,f4 every time when i will execute this html page.
promise = f1().then(f2).then(f3).then(f4); // Add handlers to be called when the Deferred object is resolved, rejected, or still in progress.
function f1() {
var d = $.Deferred();
setTimeout(function() {
// our code here....
alert("1");
console.log("1");
d.resolve(); // resolve() :Resolve a Deferred object and call any doneCallbacks with the given args.
},1000); // You set some time for each method.
return d.promise(); //promise(): Return a Deferred’s Promise object.
}
function f2() {
var d = $.Deferred();
setTimeout(function() {
alert("2");
console.log("2");
d.resolve();
},1000);
return d.promise();
}
function f4() {
var d = $.Deferred();
setTimeout(function() {
alert("4");
console.log("4");
d.resolve();
},1000);
return d.promise();
}
function f3() {
var d = $.Deferred();
setTimeout(function() {
alert("3");
console.log("3");
d.resolve();
},1000);
return d.promise();
}
</script>
Javascript without extra work is single threaded. that means functions are not able to be executed simultaneously. but the problem is that the $.get() and $.post() calls are asynchronous. that means they are executed whenever the requested data arrives your client. (first come first serve)
an solution would be to execute function B after all the results ob A arrived, or to hold back all results and handle all data at once then run update_dropdown().
A quick question on how to use Jquery.deferred to make a slow synchronous function return a promise instead.
What I've done so far is this :
function sayIt(ms) {
setTimeout( function() { console.log('what I say'); }, ms);
}
function doIt() {
return $.Deferred( function() { sayIt(2000); }).promise();
}
doIt().then( function() { console.log('ah'); });
the sayIt(2000) always goes through but the chained function after the 'then' never fires.
If I do this :
doIt().then( console.log('ah'));
the 'ah' comes up right away, and then the 'what I say' 2000ms later - what I want is of course the opposite - that after two seconds I get 'what I say' and then 'ah' right after.
Any suggestions appreciated!
To do something synchronously, but still use a promise, do:
function slowPromise() {
var def = $.Deferred();
// do something slow and synchronous
...
// resolve the deferred with the result of the slow process
def.resolve(res);
// and return the deferred
return def.promise();
}
The effect is that you still get a promise, but that promise is already resolved, so any .then() which is subsequently registered on it proceeds immediately.
The advantage of this pattern is that if you subsequently replace the synchronous code with something asynchronous the function still has the same external interface.
If you want to execute a function after the timeout has expired, you need to call resolve() on the Deferred object from within the timeout expiration function:
function sayIt(ms) {
var d = $.Deferred();
setTimeout(function() {
console.log('what I say');
d.resolve()
}, ms);
return d;
}
In this way you constrain the resolution of the Deferred object to the expiration of the timeout.
To achieve what I believe is your intent:
function doIt() {
return sayIt(2000).promise()
}
The .promise() call is optional. It only restricts the available interface for callers: by returning a Promise instead of the original Deferred object, the caller can only react to events, but not triggering them. Reference: http://api.jquery.com/deferred.promise/.
Eventually, your original call:
doIt().then( function() { console.log('ah'); });
Will output:
// 2 seconds delay
what I say
ah