23

When I have the following code:

var promise1 = Promise.resolve([1, 2, 3]);

promise1.then((value) => {
  console.log(value);
  // expected output: Array [1, 2, 3]
});


console.log('end of script');

I know that end of script is returned earlier because the promise is asynchronous. But at what point of execution does it become asynchronous?

Is Promise.resolve() asynchronous? Or is .then asynchronous or even both functions? Is there some other mechanism playing under the hood?

(was a hell to google because I get only results of the new async await features)

Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155

4 Answers4

19
 Promise.resolve([1, 2, 3]);

Is Promise.resolve() asynchronous?

No that's just a regular function call. It will return a result immediately.

Or is .then asynchronous or even both functions

No. Both aren't asynchronous in the sense that

promise1.then((value) => console.log(value));

will immediately return a new Promise for chaining.

However a Promise definitely resolves asynchronously, which means that the inner function (value => console.log(value)) is called definitely after your whole synchronous code executed.

Is there some other mechanism playing under the hood?

Yes there is a "magic" event loop in the background which manages all the async events.

Matthias
  • 13,607
  • 9
  • 44
  • 60
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • 2
    Resolving and calling the callback are two different things. I'd argue that in `Promise.resolve([1, 2, 3])`, the promise is synchronously fulfilled (resolved). Even calling the `resolve` function in a promise executor is synchronous, it changes the promise state immediately. – Bergi Feb 11 '18 at 15:45
  • @bergi with *resolves* i refer to the `then` callbacks being called not `resolve()` ... however i admit that my statement allows for interpretation... – Jonas Wilms Feb 11 '18 at 16:26
  • 1
    yeah, *[resolve](https://stackoverflow.com/a/29269515/1048572)* usually means "setting the state of the promise to *resolved*". – Bergi Feb 11 '18 at 16:43
10

All answers are nice but i would like to mention a little subtle point here. In JS not all asynchronous animals are equal. Promises use microtask queue while the oldschool async callbacks use the event queue.

So as for below code please try to guess the order of logs before you run it..

console.log("Code starts here");
setTimeout(console.log,0,"setTimeout resolved");
Promise.resolve("promise resolved")
       .then(s => (console.log(s), "yet another promise resolved"))
       .then(s => console.log(s));
console.log("Code ends here")

So as you see microtask queue which is used by Promises are privileged to the event queue and when it's time comes the instruction at the head of the microtask queue takes precedence compared to the poor one at the head of the event queue even though they both resolve at the same time just like above.

Redu
  • 25,060
  • 6
  • 56
  • 76
  • I don't think your code demonstrates this "microtask queue" if it exists. `setTimeout(0)` fires after about 4ms, so that event would fire last regardless of there being multiple queues. – mpen Sep 23 '20 at 18:48
8

Here is the exact order of what goes on. Before we begin, you should note that Promise objects are always in one of three states:

  1. Waiting for evaluation to complete.
  2. Resolved with a final value.
  3. Rejected with a "reason" value.

First, promise1 is assigned a promise that is in the "Resolved" state with a final value of [1,2,3]:

var promise1 = Promise.resolve([1, 2, 3]);

Next, we ask that, once promise1 enters its resolved state, we log its final value. However, .then(), .catch(), etc. in promises are never evaluated until the whole program is passed through and execution enters the Javascript event loop. Thus, this chunk of code registers the future action that is to be completed but does not actually complete it; this chunk of code returns right away without completion occurring.

promise1.then((value) => {
  console.log(value);
  // expected output: Array [1, 2, 3]
});

After that, we print some text:

console.log('end of script');

At this point, Javascript's execution returns to its event loop, it finds the .then() that we registered earlier, and it carries out the relevant function ((value) => console.log(value)).

There is a helpful article describing how the event loop works with promises here: https://blog.sessionstack.com/how-javascript-works-event-loop-and-the-rise-of-async-programming-5-ways-to-better-coding-with-2f077c4438b5

D. Levine
  • 319
  • 3
  • 5
5

But at what point of execution does it become asynchronous?

When something happens "out of order".

Is Promise.resolve() asynchronous?

Not usually. But yes, depending on what argument you call it with it sometimes does schedule the assimilation of a thenable for later. In your case, passing an array, no there's nothing asynchronous going on.

In any case, it always immediately returns a promise.

Or is .then asynchronous or even both functions?

Yes. then does always schedule the callback function that you pass in for later.

Of course, it does always immediately return a promise as well.

In general, we can say that observing a promise result is always asynchronous.

When asking whether a function is asynchronous, it's unfortunately ambiguous whether we mean that the function is called asynchronously (later), or causes another function to be called asynchronously (by scheduling an asynchronous event).

Bergi
  • 630,263
  • 148
  • 957
  • 1,375