I would expect the output for the following snippet to be 1, 2, 3, 4. But, the actual output order is 1, 4, 3, 2.
self.promiseChain = new Promise(function (resolve, reject) {
setTimeout(resolve, 4000);
}).then(function () {
console.log(1);
});
self.promiseChain.then(function () {
return new Promise(function (resolve, reject) {
setTimeout(resolve, 3000);
}).then(function () {
console.log(2);
});
});
self.promiseChain.then(function () {
return new Promise(function (resolve, reject) {
setTimeout(resolve, 2000);
}).then(function () {
console.log(3);
});
});
self.promiseChain.then(function () {
return new Promise(function (resolve, reject) {
setTimeout(resolve, 200);
}).then(function () {
console.log(4);
});
});
http://www.es6fiddle.net/imu5bhoj/
Everything I've read about promises indicates it should be possible to get the desired order in a 'flat' chain like this. Apparently I'm missing some detail? Could someone help point me in the right direction?
Here's a fiddle (http://www.es6fiddle.net/imu6vh1o/) for how to do it in a non-flat way, but it's harder to reason about and makes sequential chaining awkward.
I've searched similar issues on stack overflow but none of them answer the question generically using a straightforward example (that I could find).
You just attached three .then() handlers to the exact same self.promiseChain promise. This is branching, not chaining. With promises, those are very different behaviors. Those are three handlers that will all be called one immediately after the other (without waiting for results) when self.promiseChain is resolved. So, the resulting three async operations will run in parallel and finish whenever they finish, thus the results you see.
If you wanted these four operations to be sequenced, then you have to actually chain them one to another, not all chained onto the same promise. Remember .then() returns a new promise and it is that returned promise that you want to chain to in order to sequence things.
You are doing this:
var p = somePromise();
p.then(fn1);
p.then(fn2);
p.then(fn3);
This will trigger fn1, fn2 and fn3 at basically the same time and fn2 will not wait for the fn1 promise to resolve.
If you want to sequence the operations, then you want this type of logic:
var p = somePromise();
p.then(fn1).then(fn2).then(fn3);
This will not execute fn2 until the fn1 promise is done and will not execute fn3 until the fn2 promise is done - thus sequencing the async operations.
Here's how it would be if they were actually sequenced one after another. You can actually run this snippet (but have patience because it takes 10 seconds to run):
var self = {};
self.promiseChain = new Promise(function (resolve, reject) {
setTimeout(resolve, 4000);
}).then(function () {
log(1);
});
var p = self.promiseChain.then(function () {
return new Promise(function (resolve, reject) {
setTimeout(resolve, 3000);
}).then(function () {
log(2);
});
});
p = p.then(function () {
return new Promise(function (resolve, reject) {
setTimeout(resolve, 2000);
}).then(function () {
log(3);
});
});
p = p.then(function () {
return new Promise(function (resolve, reject) {
setTimeout(resolve, 200);
}).then(function () {
log(4);
});
});
p.then(function() {
// last promise is done now
log("all done");
});
function log(x) {
var div = document.createElement("div");
div.innerHTML = x;
document.body.appendChild(div);
}
See these other similar answers:
Execute native js promise in series
Understanding javascript promises; stacks and chaining
Is there a difference between promise.then.then vs promise.then; promise.then
Related
My code should wait for 4-4 seconds for both the promise to execute total 8 seconds, but it is finishing in 4 seconds only. Why?
Where I am thinking wrong?
// a promise
let promise1 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Promise resolved1')}, 4000);
});
let promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Promise resolved2')}, 4000);
});
// async function
async function asyncFunc() {
// wait until the promise resolves
let result1 = await promise1;
let result2 = await promise2;
console.log(result1);
console.log(result2);
}
// calling the async function
asyncFunc();
//expected output
**//wait for 4 seconds first**
Promise resolved1
**//wait for more 4 seconds**
Promise resolved2
//output
//waits for 4 seconds
Promise resolved1
Promise resolved2
new Promise(executor)
executor, A function to be executed by the constructor. It receives two functions as parameters: resolutionFunc and rejectionFunc. Any errors thrown in the executor will cause the promise to be rejected, and the return value will be neglected. The semantics of executor are detailed below.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
// a promise
let promise1 = () => new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Promise resolved1')}, 4000);
});
let promise2 = () => new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Promise resolved2')}, 4000);
});
// async function
async function asyncFunc() {
// wait until the promise resolves
let result1 = await promise1();
console.log(result1);
let result2 = await promise2();
console.log(result2);
}
// calling the async function
asyncFunc();
The promise 1 & 2 is already running when you declared. If you want result that you expect, you should code as above.
When using async/await, your asynchronous code with begin executing, but its resolution will jump back into the synchronous code only when you use the await keyword. When you have multiple asynchronous functions, they will only execute sequentially when you have synchronous code running in between them because when you invoke the function is when the asynchronous portion of the code begins executing. In this case, the timer starts when you invoke the function, so you need to wait for the first timer to resolve before kicking off the second timer.
See this code snippet and check out the examples in this link to clarify.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
async function sequentialStart() {
console.log('==SEQUENTIAL START==')
// 1. Execution gets here almost instantly
const slow = await resolveAfter2Seconds()
console.log(slow) // 2. this runs 2 seconds after 1.
const fast = await resolveAfter1Second()
console.log(fast) // 3. this runs 3 seconds after 1.
}
The other issue is that when you declare your functions, you run them immediately and assign their values to variables. With minimum modification to your code, you need to set up your functions like below and only call them once you're ready to start the timer.
// a promise
let promise1 = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Promise resolved1');
}, 4000);
});
};
let promise2 = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('Promise resolved2');
}, 4000);
});
};
// async function
async function asyncFunc() {
// wait until the promise resolves
let result1 = await promise1();
console.log(result1);
let result2 = await promise2();
console.log(result2);
}
// calling the async function
asyncFunc();
Simple defenation of assync await
when yo declare async a function. The function will decleared as asyncronasly the default value of function is syncronasly . asyncronas function run block level(line by line) when you add await on a promise(function that return value) because of await compiler firstly resolved the promise and then run to next line of code
I have a page that contains N html selects. I have a function called 'run_all_ajax' that loops through them and calls an ajax function that populates them. I want a promise to return from run_all_ajax only when Promise.all completes within it.
Right now, the console reads;
all done, 0
after all done
0,1,2,3, etc
meaning that the promise.all is resolving before i have added to the promises array. How do I correct this?
Also, I want to understand how the array of promises works in terms of timing. Are we assuming that we can loop through the array of selects and add them to the array of promises faster than we could resolve all outstanding promises with the Promise.all()?
function run_all_ajax() {
return new Promise(function (resolve, reject) {
var promises = [];
$("[selectgrid]").each(function (i, obj) {
$.ajax({
//stuff
success: function (response) {
//stuff
console.log(i);
}, //end: success
complete: function (jqXHR, textStatus) {//
promises.push(new Promise(function (resolve, reject) { resolve("Complete"); }));
}
}); //end: $.ajax
});
Promise.all(promises).then(function (values) {
console.log('all done, ' + promises.length);
resolve("Complete");
});
}); //end promise
}
run_all_ajax().then(function(){
console.log('after all done');
})
You push a promise at the wrong place (time). There is no need to create a new Promise. The promise you need is returned by $.ajax().
So do:
promises.push($.ajax({
//stuff
}));
promises.push is called when a request is complete which is way after Promise.all is executed.
Basically you are calling Promise.all([]) which resolves immediately.
This
new Promise(function (resolve, reject) { resolve("Complete"); })
also resolves immediately. It's equal to Promise.resolve("Complete")
var p1 = new Promise(function(resolve, reject) {
setTimeout(() => resolve("first"), 5000);
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(() => resolve("second"), 2000);
});
var p3 = new Promise(function(resolve, reject) {
setTimeout(() => resolve("third"), 1000);
});
console.log("last to print");
p1.then(()=>p2).then(()=>p3).then(()=> console.log("last to be printed"))
As I was reading about promises, I know that I can print promises synchronous (in this case print: first, second, third, last to print) when I use async /await. Now I have also been reading that the same thing can be achieved using .then chaining and async/await is nothing 'special'. When I try to chain my promises, however, nothing happens except for the console.log of "last to be printed". Any insight would be great! Thanks!!
Edit to question:
var p1 = new Promise(function (resolve, reject) {
setTimeout(() => console.log("first"), 5000);
resolve("first resolved")
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(() => console.log("second"), 2000);
resolve("second resolved")
});
var p3 = new Promise(function (resolve, reject) {
setTimeout(() => console.log("third"), 0);
resolve("third resolved")
});
console.log("starting");
p1.then((val) => {
console.log("(1)", val)
return p2
}).then((val) => {
console.log("(2)", val)
return p3
}).then((val) => {
console.log("(3)", val)
})
Loggs:
starting
(1) first resolved
(2) second resolved
(3) third resolved
third
second
first
1: if executor function passed to new Promise is executed immediately, before the new promise is returned, then why are here promises resolved ()synchronously) first and after the setTimeouts (asynchronously) gets executed?
Return value vs. resolve promise:
var sync = function () {
return new Promise(function(resolve, reject){
setTimeout(()=> {
console.log("start")
resolve("hello") //--works
// return "hello" //--> doesnt do anything
}, 3000);
})
}
sync().then((val)=> console.log("val", val))
The executor function you pass to new Promise is executed immediately, before the new promise is returned. So when you do:
var p1 = new Promise(function(resolve, reject) {
setTimeout(() => resolve("first"), 5000);
});
...by the time the promise is assigned to p1, the setTimeout has already been called and scheduled the callback for five seconds later. That callback happens whether you listen for the resolution of the promise or not, and it happens whether you listen for resolution via the await keyword or the then method.
So your code starts three setTimeouts immediately, and then starts waiting for the first promise's resolution, and only then waiting for the second promise's resolution (it'll already be resolved, so that's almost immediate), and then waiting for the third (same again).
To have your code execute those setTimeout calls only sequentially when the previous timeout has completed, you have to not create the new promise until the previous promise resolves (using shorter timeouts to avoid lots of waiting):
console.log("starting");
new Promise(function(resolve, reject) {
setTimeout(() => resolve("first"), 1000);
})
.then(result => {
console.log("(1) got " + result);
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("second"), 500);
});
})
.then(result => {
console.log("(2) got " + result);
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("third"), 100);
});
})
.then(result => {
console.log("(3) got " + result);
console.log("last to print");
});
Remember that a promise doesn't do anything, and doesn't change the nature of the code in the promise executor. All a promise does is provide a means of observing the result of something (with really handy combinable semantics).
Let's factor out the common parts of those three promises into a function:
function delay(ms, ...args) {
return new Promise(resolve => {
setTimeout(resolve, ms, ...args);
});
}
Then the code becomes a bit clearer:
function delay(ms, ...args) {
return new Promise(resolve => {
setTimeout(resolve, ms, ...args);
});
}
console.log("starting");
delay(1000, "first")
.then(result => {
console.log("(1) got " + result);
return delay(500, "second");
})
.then(result => {
console.log("(2) got " + result);
return delay(100, "third");
})
.then(result => {
console.log("(3) got " + result);
console.log("last to print");
});
Now, let's put that in an async function and use await:
function delay(ms, ...args) {
return new Promise(resolve => {
setTimeout(resolve, ms, ...args);
});
}
(async() => {
console.log("starting");
console.log("(1) got " + await delay(1000, "first"));
console.log("(2) got " + await delay(500, "second"));
console.log("(3) got " + await delay(100, "third"));
console.log("last to print");
})();
Promises make that syntax possible, by standardizing how we observe asynchronous processes.
Re your edit:
1: if executor function passed to new Promise is executed immediately, before the new promise is returned, then why are here promises resolved ()synchronously) first and after the setTimeouts (asynchronously) gets executed?
There are two parts to that question:
A) "...why are here promises resolved ()synchronously) first..."
B) "...why are here promises resolved...after the setTimeouts (asynchronously) gets executed"
The answer to (A) is: Although you resolve them synchronously, then always calls its callback asynchronously. It's one of the guarantees promises provide. You're resolving p1 (in that edit) before the executor function returns. But the way you're observing the resolutions ensures that you observe the resolutions in order, because you don't start observing p2 until p1 has resolved, and then you don't start observing p3 until p2 is resolved.
The answer to (B) is: They don't, you're resolving them synchronously, and then observing those resolutions asynchronously, and since they're already resolved that happens very quickly; later, the timer callbacks run. Let's look at how you create p1 in that edit:
var p1 = new Promise(function (resolve, reject) {
setTimeout(() => console.log("first"), 5000);
resolve("first resolved")
});
What happens there is:
new Promise gets called
It calls the executor function
The executor function calls setTimeout to schedule a callback
You immediately resolve the promise with "first resolved"
new Promise returns and the resolved promise is assigned to p1
Later, the timeout occurs and you output "first" to the console
Then later you do:
p1.then((val) => {
console.log("(1)", val)
return p2
})
// ...
Since then always calls its callback asynchronously, that happens asynchronously — but very soon, because the promise is already resolved.
So when you run that code, you see all three promises resolve before the first setTimeout callback occurs — because the promises aren't waiting for the setTimeout callback to occur.
You may be wondering why you see your final then callback run before you see "third" in the console, since both the promise resolutions and the console.log("third") are happening asynchronously but very soon (since it's a setTimeout(..., 0) and the promises are all pre-resolved): The answer is that promise resolutions are microtasks and setTimeout calls are macrotasks (or just "tasks"). All of the microtasks a task schedules are run as soon as that task finishes (and any microtasks that they schedule are then executed as well), before the next task is taken from the task queue. So the task running your script does this:
Schedules a task for the setTimeout callback
Schedules a microtask to call p1's then callback
When the task ends, its microtasks are processed:
The first then handler is run, scheduling a microtask to run the second then handler
The second then handler runs and schedules a micro task to call the third then handler
Etc. until all the then handlers have run
The next task is picked up from the task queue. It's probably the setTimeout callback for p3, so it gets run and "third" appears in the console
Return value vs. resolve promise:
The part you've put in the question doesn't make sense to me, but your comment on this does:
I read that returning a value or resolving a promise is same...
What you've probably read is that returning a value from then or catch is the same as returning a resolved promise from then or catch. That's because then and catch create and return new promises when they're called, and if their callbacks return a simple (non-promise) value, they resolve the promise they create with that value; if the callback returns a promise, they resolve or reject the promise they created based on whether that promise resolves or rejects.
So for instance:
.then(() => {
return 42;
})
and
.then(() => {
return new Promise(resolve => resolve(42));
})
have the same end result (but the second one is less efficient).
Within a then or catch callback:
Returning a non-promise resolves the promise then/catch created with that value
Throwing an error (throw ...) rejects that promise with the value you throw
Returning a promise makes then/catch's promise resolve or reject based on the promise the callback returns
You cannot make asynchronous code execute synchronously.
Even async / await are just syntax that gives you a synchronous-style control flow inside a promise.
When I try to chain my promises, however, nothing happens except for the console.log of "last to be printed". Any insight would be great!
The other functions don't generate any output. That has nothing to do with them being in promises.
You start three timers (all at the same time), then log 'last to print', then chain some promises so that 'last to be printed' will print when all three promises resolve (5 seconds after you start them all going).
If you want the timers to run sequentially, then you have to initiate them only when the previous one has finished, and if you want to see what they resolve with then you have to write code that actually looks at that.
function p1() {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("first"), 5000);
});
}
function p2() {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("second"), 2000);
});
}
function p3() {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("third"), 1000);
});
}
function log(value) {
console.log("Previous promise resolved with " + value);
}
p1()
.then(log)
.then(p2)
.then(log)
.then(p3)
.then(log)
.then(() => console.log("last to be printed"));
Async/await is, arguably, neater:
function p1() {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("first"), 5000);
});
}
function p2() {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("second"), 2000);
});
}
function p3() {
return new Promise(function(resolve, reject) {
setTimeout(() => resolve("third"), 1000);
});
}
function log(value) {
console.log("Previous promise resolved with " + value);
}
(async function() {
log(await p1());
log(await p2());
log(await p3());
console.log("last to be printed");
}());
If you need to call an await but the function that contains that await doesn't have to be async, because you need, for example, a "number" and not a "Promise number ", you can do de next:
var ex: number = new Number(async resolve => {
var f = await funcionExample();
resolve(f);
}).valueOf();
I ran into a bug in my code that puzzled me for a long time and am looking for some clarification.
In this code, the commented out inner promise was causing a problem. The Promise.all() at the end was continuing as soon as the setTimeout hit, not after the resolve inside the timeout.
Wrapping the async code with a promise fixes the flow problem, but why is this?
Essentially, why can't we just run normal async code in a .then() chain, an return a Promise.resolve() at the end of the async callback?
var asyncPromise = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('Async Promise done');
resolve();
}, 1000);
});
};
var generateSignupPromises = function(qty) {
var promiseArray = [];
for (var i = 1; i <= qty; i++) {
promiseArray.push(
function() {
return asyncPromise()
.then(function() {
console.log('Before Timeout');
//Uncommenting this fixes the issue
//return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('After Timeout');
//resolve();
return Promise.resolve();
}, 500);
//})
});
}
);
}
return promiseArray;
};
var test = generateSignupPromises(1);
Promise.all([test[0]()])
.then(function() {
console.log('Done');
});
Link to running code: http://www.es6fiddle.net/imfdtuxc/
why can't we just run normal async code in a .then() chain, an return a Promise.resolve() at the end of the async callback?
You perfectly can. But any value - be it a promise or whatever - being returned from a plain asynchronous callback is just ignored as usual.
There is nothing that starting the asynchronous action inside a then callback changes about this, setTimeout just doesn't return a promise - and the then won't know about anything asynchronous happening that it could wait for.
If you want to return a promise from a callback and get another promise for that eventual result, it has to be a then callback:
asyncPromise()
.then(function() {
return new Promise(function(resolve, reject) {
// ^^^^^^
setTimeout(resolve, 500);
}).then(function() {
// ^^^^^^^^^^^^^^^
return Promise.resolve();
});
});
Then is a sync function so if you want to do async task inside then, you has to return a Promise.
Also, Promise.all expect an array of promises. Not an array of an array.
var asyncPromise = function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('Async Promise done');
resolve();
}, 1000);
});
};
var generateSignupPromises = function(qty) {
var promiseArray = [];
for (var i = 1; i <= qty; i++) {
promiseArray.push(
function() {
return asyncPromise()
.then(function() {
console.log('Before Timeout');
//Uncommenting this fixes the issue
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log('After Timeout');
resolve();
//return Promise.resolve();
}, 500);
})
});
}
);
}
return promiseArray;
};
var test = generateSignupPromises(1);
Promise.all([test[0]()])
.then(function() {
console.log('Done');
});
http://www.es6fiddle.net/imfe2sze/
How could I fire off promises one after the other?
waitFor(t), is a function that returns a promise that resolves after t time. What I wish to be able to do with that is:
waitFor(1000) Then when finished, console.log('Finished wait of 1000 millis') then
waitFor(2000) Then when finished, console.log('Finished wait of 2000 millis') then
waitFor(3000) Then when finished, console.log('Finished wait of 3000 millis')
Here is what I tried:
waitFor(1000).then(function(resolve, reject) {
console.log(resolve);
}).then(waitFor(2000).then(function(resolve, reject) {
console.log(resolve);
})).then(waitFor(3000).then(function(resolve, reject) {
console.log(resolve);
}));
Unfortunately this console.logs the statements each 1 second after another, which means that the promises where all called at once.
I managed to fix this with callbacks like so, yet that makes everything very ugly:
waitFor(1000).then(function(resolve, reject) {
console.log(resolve+' # '+(new Date().getSeconds()));
waitFor(2000).then(function(resolve, reject) {
console.log(resolve+' # '+(new Date().getSeconds()));
waitFor(3000).then(function(resolve, reject) {
console.log(resolve+' # '+(new Date().getSeconds()));
});
});
});
So how should I do this with promises that makes it work, yet isn't using ugly callback hell?
Undesired result: http://jsfiddle.net/nxjd563r/1/
Desired result: http://jsfiddle.net/4xxps2cg/
I found your solution.
You need to have each then to return a new promise, so that the next then can react once the previous one has been resolved.
waitFor(1000).then(function(result) {
$('#result').append(result+' # '+(new Date().getSeconds())+'<br>');
return waitFor(2000);
}).then(function(result) {
$('#result').append(result+' # '+(new Date().getSeconds())+'<br>');
return waitFor(3000);
}).then(function(result) {
$('#result').append(result+' # '+(new Date().getSeconds())+'<br>');
});
jsfiddle http://jsfiddle.net/4xxps2cg/2/
You can put promises into array and use reduce to chain them, starting with one extra resolved promise.
function waitPromise(time) {
//console.log(time);
return new Promise( (resolve,reject) => {
setTimeout( () => {resolve('resolved');}, time);
});
}
function log(data) {
return new Promise( (resolve,reject) => {
console.log( data +' # '+(new Date().getSeconds()));
resolve();
});
}
var ps = [];
for (var i=0;i<3;i++) {
let time = (i+1) * 1000;
ps.push( () => waitPromise(time) );
ps.push( log );
}
console.log( 'started' +' # '+(new Date().getSeconds()));
var p = Promise.resolve();
ps.reduce( (p,c) => {return p.then(c)}, p);
The format for calling and waiting is a bit off, your then should be a function that returns a promise, since now you're passing a function call instead of a function, its running that request instantly instead of waiting to call the function as a result of the promise.
This should do it:
function waitFor(timeout) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(`Finished waiting ${timeout} milliseconds`);
}, timeout);
});
}
waitFor(1000).then(function(resolve, reject) {
$('#result').append(resolve+' # '+new Date().getSeconds()+'<br/>');
}).then(function(){
return waitFor(2000)
}).then(function(resolve, reject) {
$('#result').append(resolve+' # '+new Date().getSeconds()+'<br/>');
}).then(function() {
return waitFor(2000)
}).then(function(resolve, reject) {
$('#result').append(resolve+' # '+new Date().getSeconds()+'<br/>');
})
waitFor() appear to be called immediately at .then() ; try returning waitFor() from within .then() anonymous function.
Could alternatively create array of duration values , use Array.prototype.shift() to call waitFor with each duration value in succession , or pass parameter timeout to waitFor ; if same process called at each .then() , include process at .then() chained to Promise in waitFor ; call same function waitFor at .then() chained to initial waitFor() call
var t = [1000, 2000, 3000];
function waitFor(timeout) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("`Finished waiting ${timeout} milliseconds`");
}, timeout && t.shift() || t.shift());
}).then(function (data) {
$('#result').append(data + ' # ' + new Date().getSeconds() + '<br/>');
})
}
waitFor().then(waitFor).then(waitFor)
//.then(function() {return waitFor(5000)})