Why does a function called after my promise execute before the promise's callback?
I read this in MDN, but didn't understand it
"Callbacks will never be called before the completion of the current
run of the JavaScript event loop."
I thought it meant that if I have any other statements after resolve() or reject() they will get executed before the callback is invoked. Though, that seems to be an incomplete understanding.
function myFunction() {
return new Promise( function(resolve, reject) {
const err = false;
if(err) {
reject("Something went wrong!!!");
}
else {
resolve("All good");
}
});
}
myFunction().then(doSuccess).catch(doError);
doOther();
function doError(err) {
console.log(err);
}
function doSuccess() {
console.log('Success');
}
function doOther() {
console.log("My Other Function");
}
Output:
My Other Function
Success
By specification, a promise .then() or .catch() callback is never called synchronously, but is called on a future tick of the event loop. That means that the rest of your synchronous code always runs before any .then() handler is called.
So, thus your doOther() function runs before either doSuccess() or doError() are called.
Promises are designed this way so that a promise .then() handler will be called with consistent timing whether the promise is resolved immediately or resolved some time in the future. If synchronous .then() handlers were allowed, then calling code would either have to know when it might get called synchronously or you'd be susceptible to weird timing bugs.
In the Promises/A+ specification which the promises in the ES6 specification were based on, it defines a `.then() handler like this:
promise.then(onFulfilled, onRejected)
and then has this to say about it:
2.2.4. onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].
And, then it defines platform code like this:
Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.
Basically what this means is that .then() handlers are called by inserting a task in the event loop that will not execute until the currently running Javascript finishes and returns control back to the interpreter (where it can retrieve the next event). So, thus any synchronous Javascript code you have after the .then() handler is installed will always run before the .then() handler is called.
I had similar confusions about what it means by executing after the current loop. I was going through MDN docs on Promises, which says the following:
Callbacks added with then() will never be invoked before the completion of the current run of the JavaScript event loop.
This website http://latentflip.com/loupe/ video expains it pretty well, basically api's like setTimeout execute after the inbuilt js functions. But, the problem with callbacks is, if it doesn't use those apis then it might execute before the finish of current run of the event loop. Following examples show the difference:
Old school callbacks
var foo = function(then1) {
console.log("initial");
var i = 0;
while (i < 1000000000) {
i++;
}
then1();
}
function then11() {
console.log("res");
}
foo(then11);
console.log("end"); // unlike Promises, end is printed last
New Promise
var promise = new Promise(function(resolve, reject) {
console.log("Initial");
//while loop to 10000
var i = 0;
while(i<1000000000) { //long async task without ext apis
i++;
}
resolve("res");
});
promise.then(function(result) {
console.log(result); // "Stuff worked!"
});
console.log("end"); // end is printed before res!!!
Related
Loop inside of the promise works like sync code, for example:
console.log('im working')
function proLoop(){
return Promise((resolve ,rejects)=>{
for (let i = 0; i < 1000000000000; i++) {}
console.log('loop is done')
})
}
proLoop();
console.log('im working')
So even if we write is like promise it will get more time and freezes our code In other words it will works synchronically.
i find a solution but why it works?
so the solution is just warp your code as like resolved promise
like this
return new Promise.resolve().then( ()=>{
for (let i = 0; i < 1000000000000; i++) {}
console.log('loop is done')
})
but why and how???
Couple of things you need to understand here:
Promises don't make something asynchronous - they are a notification mechanism for something that's already asynchronous. Promises notify you of the success or failure of an operation that's already asynchronous.
Callback function of the promise constructor is called synchronously; it is called synchronously to start an operation that's already asynchronous.
In your case, promise constructor contains synchronous code; this is why it blocks other code.
Moving the loop inside the callback function of then executes the loop asynchronously because the callback function of then is invoked asynchronously.
Note: Even though the callback function of then method is invoked asynchronously, once it starts executing, no other code will execute until the synchronous code inside the callback is executed completely.
In both cases, the for loop will block the main event loop. The difference is when the for loop starts.
In the first case, the function passed to new Promise is executed immediately. It therefore blocks the rest of the function that creates it.
In the second case, the function passed to then() is queued up to run next time the event loop is free. The function that created it therefore finishes first and then the for loop runs. (If that's the goal, then its a pretty unintuitive approach, and using setImmediate (in browsers) or Node's process.nextTick() would be neater.)
If you wanted to shunt the work done by the for loop off the main event loop so it didn't block anything you would use a Web Worker or Worker thread depending on what JavaScript runtime you were using.
What does resolve actually do?
Consider the code below.
It prints : 1 3 4 5 6 9 7 10 11 2.
Irrespective of where resolve is written, it prints the same!
Can someone explain why this happens?
new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
resolve();
new Promise((resolve, reject) => {
console.log(3);
resolve();
})
.then(() => {
console.log(4);
})
.then(() => {
console.log(9);
})
.then(() => {
console.log(10);
})
.then(() => {
console.log(11);
})
;
// resolve()
}).then(() => {
console.log(5);
new Promise((resolve, reject) => {
console.log(6);
resolve();
}).then(() => {
console.log(7);
});
})
What does 'resolve' actually do?
Calling resolve(x) does three things.
It changes the internal state of the promise to fulfilled. Once the state is changed to fulfilled, the promise state cannot be changed again. This is a one-way, permanent change.
It sets the value x (whatever single argument you pass to resolve) as the resolved value of the promise (this is stored internal to the promise). If nothing is passed to resolve(), then the resolved value is undefined.
It inserts an event into the event queue to trigger the .then() handlers of this current promise to get called upon an upcoming cycle through the event loop. This schedules the .then() handlers to run after the current thread of Javascript execution finishes.
I'll explain the sequence you see in the console, but first here are a few points that will help to understand this:
The promise executor function (the callback passed to new Promise(fn)) is called synchronously (in the midst of the current thread of execution).
When a setTimeout() timers fires (internal to the JS engine), the timer callback is inserted in the event queue and will be picked up on a future cycle of the event loop.
When a promise resolves, an event is inserted into the event queue and will be picked up on a future cycle of the event loop.
There are multiple types of event queues in the event loop and not all have the same priority. In general promise events will be picked up before most other types of events though it's possible this can vary a bit according to the implementation. So, when multiple types of events are both put in the event queue so they are in there at the same time, this can affect which one gets called first.
Multiple .then() or .catch() handlers that are added to the event queue are handled in the order (relative to each other) that they were originally triggered in a FIFO basis (first-in-first-out).
When promise chaining with something like fn().then(f1).then(f2).then(f3) keep in mind that each .then() returns a new promise that will have its own time that it gets resolved or rejected, after the one before it and depending upon what happens in its handler function.
So, here's the sequence of events in your code:
The first promise executor function is called, thus you get the output 1
A timer is created with a timeout of 0. At some point very soon, a timer callback event will be added to the event queue.
You call resolve() on that first promise. This inserts an event/task into the promise queue to call its .then() handlers on a future cycle of the event loop. The rest of this sequence of Javascript code continues to execute. But, notice that there are not yet any .then() handlers on that first promise as its chained .then() methods haven't yet been executed.
You create a second promise and its executor function is called immediately which outputs 3.
You call resolve() on that second promise. This inserts an event/task into the promise queue to call its .then() handlers on a future cycle of the event loop. The rest of this sequence of Javascript code continues to execute.
.then() is called on that second promise. This registers a .then() handler callback function in that second promise (adds it to an internal list) and returns a new promise.
.then() is called on that newly returned promise (third promise). This registers a .then() handler callback function in that third promise (adds it to an internal list) and returns a new promise.
.then() is called on that newly returned promise (fourth promise). This registers a .then() handler callback function in that fourth promise (adds it to an internal list) and returns a new promise.
.then() is called on that newly returned promise (fifth promise). This registers a .then() handler callback function in that fifth promise (adds it to an internal list) and returns a new promise.
The executor function from the very first promise finally returns.
.then() is called on the very first promise. This registers a .then() handler callback function in that first promise (adds it to an internal list) and returns a new promise.
Because the .then() handler from the second promise ran before the .then() handler from the first promise, it gets put into the tasks queue first and thus you get the output 4 next.
When this .then() handler runs, it resolves the promise that it created earlier, the third promise and it adds a task to the promise queue to run its .then() handlers.
Now, the next item in the task queue is the .then() handler from the first promise so it gets a chance to run and you see the output 5.
This then creates another new promise with new Promise(...) and runs its executor function. This causes the output 6 to show.
This new promise is resolved with resolve().
Its .then() is called which registers a .then() callback and returns a new promise.
The current sequence of Javascript is done so it goes back to the event loop for the next event. The next thing that was scheduled was the .then() handler for the fourth promise so it gets pulled from the event queue and you see the output 9.
Running this .then() handler resolved the fifth promise and inserts its .then() handler into the promise task queue.
Back to the event queue for the next promise event. There we get the .then() handler from the final new Promise().then() in the code and you get the output 7.
The above process repeats and you see the outputs 11, then 12.
Finally, the promise task queue is empty so the event loop looks for other types of events that aren't as high a priority and finds the setTimeout() event and calls its callback and you finally get the output 2.
So, setTimeout() goes last here for a couple of reasons.
Promise events are run before timer events (in ES6), so any queued promise events are served before any queued timer event.
Because all of your promises resolve without actually having to wait for any other asynchronous events to complete (which is kind of not real-world behavior and not typically how or why one uses promises), the timer has to wait until they're all done before it gets its chance to run.
And, a few other comments:
Figuring out the relative firing order of various .then() handlers in different and independent promise chains is sometimes possible (it's only possible here because there are no real asynchronous promise resolves with uncertain resolution times), but if you really need a specific execution order, then it's better to just chain your operations to explicitly specify the order you want things to run in the code. This removes any dependency on minute implementation details of the local Javascript engine and makes the code a ton more self-explanatory. In other words, someone reading your code doesn't have to go through the 22 steps I listed to follow the desired execution order. Instead, the code will just specify the order by direct promise chaining.
In real code, it's unusual to have the orphaned, disconnected promise chains you create inside .then() handlers. Because you are not returning those promise from the .then() handler and thus inserting them in the parent promise chain, there is no way to communicate results or errors back from those disconnected promises chains. While there is very occasionally a reason to code a fire-and-forget operation that doesn't need to communicate at all with the outside world, that is unusual and is usually a sign of problem code that doesn't properly propagate errors and whose results aren't properly synchronized with the rest of what's going on.
when I place 'resolve' behind, it prints the same!
As you've discovered, this doesn't really change anything. The .then() following the new Promise(...) isn't executed until after the executor function finishes running and returns so it doesn't really matter where inside the executor you call resolve(). Said another way, none of the .then() handlers can even be registered until after the promise executor returns so no matter where you call resolve() in the promise executor, the result is the same.
resolve indicate the completion of asynchronous task.
In the below code,
new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
resolve();
new Promise((resolve, reject) => {
console.log(3);
resolve();
})
.then(() => {
console.log(4);
})
You have created new Promise, and immediately resolved it using resolve(), so it does not wait for setTimeout to get executed. The resolve(); is immediately followed by
new Promise, which creates new Promise followed by the execution of immediate then section.
In .then you have not returned any thing, so your then's are not chained properly. Return the value in then to chain it properly.
new Promise((resolve) => {
console.log("1");
setTimeout(() => {
resolve(2);
});
}).then((val) => {
console.log(val);
return "3";
}).then((val) => {
console.log(val);
return "4";
}).then((val) => {
console.log(val);
});
I am new to asynchronous JavaScript, while learning Promise in JavaScript, I wrote a simple program
var p=new Promise(function(resolve,reject)
{
//Any async task.
var IsPromiseFulfilled=true;
if(IsPromiseFulfilled){
resolve("Promise Fulfilled");
}
else
{
reject("Promise Rejected");
}
});
p.then(function(status){
console.log(status);
}).catch(function(status){
console.log(status);
});
console.log("End Of Program");
The Output was:
End Of Program
Promise Fulfilled
Can anyone please tell me why "End Of Program" was printed earlier than "Promise Fulfilled"
Because it's executed outside of your promises and in turn executes before the promises resolve.
Although the Promise.resolve().then() call isn't slow, it will process all the code then start resolving the promises.
It's also worth noting you can shorten things a little as well by using promises like:
Promise.resolve().then(result => {
// do something with your result
}).catch(error => {
// do something with your error.
});
I find this format easier than using new Promise(function (resolve, reject) {})
It works this way because of the way .then() handlers are described in the promise specification.
All .then() handlers are executed on a future tick of the event loop. That means that any synchronous code executes before any .then() handler even if the promise is resolved immediately.
Here's a very simple example:
console.log("a");
Promise.resolve().then(() => {console.log("b");});
console.log("c");
This will output:
a
c
b
This is per the promise specification and it is done this way to guarantee that .then() handler are ALWAYS asynchronous and thus have a consistent and predictable behavior, regardless of whether the promise is resolved immediately or some time in the future. It makes writing and testing code a lot simpler.
From the Promises A+ specification:
2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].
"platform code" here means that the current execution of Javascript finishes and then when the stack is completely empty of any Javascript, then and only then are promises .then() handlers called.
So, in my example above, the promise is resolved immediately, and the .then() handler is scheduled immediately, but it is scheduled to run AFTER the rest of the synchronous code finishes (essentially on the next turn of the event loop).
In the ES6 specification, when a promise resolves, its .then() handlers are scheduled with enqueJob(). The concept of jobs in ES6 is described here. What's relevant here is that they run AFTER the currently executing Javascript is done.
p.then happens in the future. While node waits for the then promise to resolve it will execute the next line of code.
Which is the console.log("End Of Program");
If you want to execute your Promises and async functions in a linear way, you must use the
ES2017 async/await syntax
Any Promise inside a async function can use the syntax await, for that you don't have to use .then() or .catch()
(async function () {
try {
var status = await p()
console.log(status)
console.log("End Of Program")
} catch (e) {
console.log(e) //If p reject, you catch it here
}
})()
And you should write your Promise like this
var p = new Promise(function(resolve,reject) {
/* When you use asynchronous functions, they all have a callback
This callback may have some error and data params, so,
you use them to resolve or reject your promise
*/
someAsyncFunction('blabla', function(error, data) {
if (error)
reject(error)
else
resolve(data)
})
})
I don't pretend for academic answer but I already asked amost the same question
today, about promises.
Actuall answer is:
When you ask to do work in JS, what is says that, "OK, this is going to take some time, but I promise that I'll let you know after the work is done. So please have faith on my promise, I'll let you know once the work is complete", and it immediately gives you a promise to you.
That's why you see your:
End Of Program
Promise Fullfilled
The actuall scheme looks like this:
│
├┐
│↓ promise
↓
console.log
I have a function that does a bunch of work then returns a resolved Promise. Is there a difference in the timing when each will be resolved?
Option 1
function returnPromise() {
// do a bunch of stuff
return Promise.resolve();
}
and this way:
Option 2
function returnPromise() {
return new Promise((resolve, reject) => {
//do a bunch of stuff
resolve();
});
}
Does Option 1 release control after all the work is done, and Option 2 release control as soon as the function is called? I feel like this has root in the fact I don't fully understand the event loop. Thanks in advance for helping me understand this.
Is there a difference in the timing when each will be resolved?
No difference. The Promise executor (the callback you pass to new Promise()) is called immediately and synchronously. So, in BOTH cases, you are immediately and synchronously returning an already resolved promise and all the code in your function has already executed.
There should be no meaningful difference in execution timing. Of course, one might take slightly different number of CPU cycles to execute, but both have the exact same outcome and both immediately return a promise that is already resolved so there should be no difference to the calling code at all.
Promise.resolve() is just meant as a more compact (and probably more efficient) means of creating an already resolved promise.
Does Option 1 release control after all the work is done, and Option 2 release control as soon as the function is called?
They both return when all your work is done and they return an already resolved promise. This is because the executor callback to new Promise() is called synchronously (before your function returns).
I feel like this has root in the fact I don't fully understand the event loop. Thanks in advance for helping me understand this.
In this particular circumstance, all your code is run synchronously so there is no particular involvement of the event loop. The returnPromise() function returns (in both cases) when your code in the function is done executing synchronously. There is no async code here.
The event loop gets involved when you do .then() on the returned promise because even though the promise (in both cases) is already resolved, the .then() handler gets queued in the event queue and does not run until the rest of your Javascript after your .then() handler is done executing.
console.log("1");
returnPromise().then(function() {
console.log("2");
});
console.log("3");
This will generate identical output results:
1
3
2
with both versions of your returnPromise() function because .then() handlers are queued until the next tick of the event loop (e.g. after the rest of your current Javascript thread of execution is done).
Is there a difference with doing it this way?
No, both your examples do the exact same thing.
Promise.resolve and Promise.reject are simply static methods on the Promise Class that help you avoid constructing a whole Promise when you don't really need to.
For the below code
function inner () {
new Promise(function(resolve,reject){
resolve()
}).then(function(){
console.log('Inner Promise')
})
}
function outer() {
return new Promise(function(resolve, reject){
resolve()
inner()
})
}
outer().then(function(data) {
console.log('Outer Promise')
})
The output is
Inner Promise
Outer Promise
I thought the outer resolve would be the first to enter the JS Message Queue followed by the inner resolve.
However the JS Event Loop fires the Inner resolve first then followed by Outer resolve.
What does Promise resolve do internally?
In a nutshell, you get the behavior you see because the .then() method on the inner() promise runs first before the .then() method on the outer() promise and thus it's handler gets queued first (see step by step explanation below for why this is).
What does Promise resolve do internally?
resolve() changes the internal state of the promise to Fulfilled. At that moment, if there are any .then() handlers already attached to the promise, they are added to a queue to be executed when the stack unwinds and the current running path of Javascript finishes and returns control back to the system. Note, as you will see in this case (when you read the step-by-step analysis below), if there are not yet any .then() handlers that have been registered, nothing can yet be added to the queue.
I thought the outer resolve would be the first to enter the JS Message
Queue followed by the inner resolve. However the JS Event Loop fires
the Inner resolve first then followed by Outer resolve.
Promise resolve actions are not added to the queue. resolve() is synchronous. It changes the state of the current promise to the Fulfilled state immediately. If, at the time the promise is resolved, there are any .then() handlers already register, then they are what is added to a queue. But, in both your promises, at the moment each of your promises are resolved, there are no .then() handlers yet attached. So, those .then() handlers won't be queued at the point the promise is resolved. Instead, they will be queued later when the .then() method actually runs and registers them.
Here's a bit of an analysis of how your code runs and a likely explanation:
First you call outer(). This creates a Promise object and synchronously calls the promise executor callback you pass it.
That callback calls resolve() which will queue up the calling of any currently attached .then() handlers. Note, that at the moment you call resolve(), there are no .then() handlers yet because in this code outer().then(), you're still running outer() and the .then() after it has not yet run so there isn't actually yet anything to queue up yet (this is probably key to the ordering you observe - read on for further details).
Then, the code calls inner(). That creates a new promise and then (still running synchronously) calls the promise executor callback you pass there which calls resolve(). Again, there are not yet any .then() handlers attached so there is still yet nothing else to schedule for future execution.
Now, the Promise executor inside of inner() returns and the .then() method is called on that promise inside of inner(). This promise has already been resolved so, when this .then() handler is called, the promise knows to schedule it to run in the future. Since all .then() handlers are called asynchronously when the stack has unwound to only platform code, it is not run immediately, but it is scheduled to run in the future by puttiing it in a queue. It is implementation dependent exactly how this queue works (macro task or micro task, etc...), but we know it is guaranteed by the Promise specification to run after the current synchronous piece of JS code that is executing finishes running and returns control back to the system.
Now inner() returns (code is still running synchronously).
Now outer() returns and the .then() method in outer().then() runs. Just like in the previous example, when this .then() method is called, the host promise is already resolved. So, the promise engine will schedule the .then() handler callback to be run by adding it to the queue.
If these two .then() handlers in steps 4 and 6 are queued in the order they were run (which would be the logical implementation), then you would see the .then() handler on inner() run first and then the .then() handler on outer() would run since inner().then() ran first beforeouter().then()`. That is what you observe.
Even though outer() is resolved before inner() is, at the time outer() is resolved, there are not .then() handlers attached so there is nothing to schedule for future execution when it is resolved. This is likely why even though it is resolved first, its .then() handlers don't run first. Once both inner() and outer() are resolved, it is inner's .then() method that runs first, so it gets first crack at scheduling a .then() handler to run and this is what you observe.
You can get some additional context for what's going on by reading and studying these references:
What is the order of execution in javascript promises
Difference between microtask and macrotask within an event loop context.
If you wanted to more explicitly specify that the inner .then() handler would fire first, you can simply chain it to the outer() promise like this:
function inner () {
return new Promise(function(resolve,reject){
resolve();
}).then(function(){
console.log('Inner Promise')
})
}
function outer() {
// Add return here to chain the inner promise
// make to make sure that outer() does not resolve until
// inner() is completely done
return inner();
}
outer().then(function(data) {
console.log('Outer Promise')
})
If you wanted to guarantee that the outer().then() handler was called first, you'd have to pick a different structure since this structure does not force that type of order in any way and can't be cajoled that direction unless you consciously delay the running of inner() (using a setTimeout() or some such thing) or restructure the code. For example, if you really wanted to restructure to force inner() to run last, you would kick it off in the outer().then() handler like this:
function inner () {
return new Promise(function(resolve,reject){
resolve()
}).then(function(){
console.log('Inner Promise')
})
}
function outer() {
return new Promise(function(resolve, reject){
resolve()
})
}
outer().then(function(data) {
console.log('Outer Promise')
return inner();
})
I thought the outer resolve would be the first to enter the JS Message Queue followed by the inner resolve.
Yes, the "outer" promise is resolved first. Put a console.log right next to the resolve call.
But no, the outer then callback is not put in the queue first because it installed after the inner then callback. What you are doing is essentially equivalent to
var outer = Promise.resolve();
var inner = Promise.resolve();
inner.then(function() {
console.log('Inner Promise')
});
outer.then(function(data) {
console.log('Outer Promise')
});
but obfuscated due to the nested (synchronous) function calls.