Reputation: 435
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);
});
})
Upvotes: 0
Views: 622
Reputation: 707158
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:
new Promise(fn)
) is called synchronously (in the midst of the current thread of execution).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..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).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:
1
0
. At some point very soon, a timer callback event will be added to the event queue.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.3
.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..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..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..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..then()
handler from the first promise so it gets a chance to run and you see the output 5
.new Promise(...)
and runs its executor function. This causes the output 6
to show.resolve()
..then()
is called which registers a .then()
callback and returns a new promise..then()
handler for the fourth promise so it gets pulled from the event queue and you see the output 9
..then()
handler resolved the fifth promise and inserts its .then()
handler into the promise task queue..then()
handler from the final new Promise().then()
in the code and you get the output 7
.11
, then 12
.setTimeout()
event and calls its callback and you finally get the output 2
.So, setTimeout()
goes last here for a couple of reasons.
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.
Upvotes: 3
Reputation: 7891
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);
});
Upvotes: 2