2

I was expecting the following snippet to hang forever since the promise is never neither fulfilled nor rejected, instead the JavaScript runtime is simply terminated and the code after the await is never executed.

(async function () {
    console.log('so far so good');
    await new Promise(() => {});
    console.log('never printed');
})();

What's worse is that the above also happens dynamically, that is when the Promise becomes impossible to fulfill/reject after a certain event, for example the following only keep the runtime alive for one second:

(async function () {
    console.log('so far so good');
    await new Promise((fulfill, reject) => {
        const timeout = setTimeout(fulfill, 2000);
        setTimeout(() => {
            clearTimeout(timeout);
        }, 1000);
    });
    console.log('never printed');
})();

This is counterintuitive to say the least, what's the rationale behind this? More importantly can you link me to a document/spec that deals with this behavior?

cYrus
  • 2,976
  • 6
  • 29
  • 47
  • 1
    Sorry, but I don't really get it. What do you mean by *blocking*? – Vinz243 May 01 '17 at 21:19
  • More importantly, what shows that is behind blocked only for 1s and then the rest is never executed? – Vinz243 May 01 '17 at 21:21
  • 1
    I think you are confusing "blocking" with "keeping the runtime alive" – Bergi May 01 '17 at 21:24
  • By "blocking" I mean preventing the runtime from terminating, I'm aware that it's not really blocked. Picked the wrong term, sorry. – cYrus May 01 '17 at 21:46
  • 2
    An unfulfilled promise does not keep node.js alive by itself. It takes an underlying uncompleted async operation that is still alive (usually with some native code behind it) for node.js to automatically stay alive. Examples of things that automatically keep node.js alive are open sockets, timers that haven't fired, etc... An unfulfilled promise is just a Javascript object sitting in memory. It has no more effect on the lifetime of a node.js process than any other object in node.js. – jfriend00 May 01 '17 at 21:54
  • Vinz243: you can figure it out by running the example in Node.js – cYrus May 01 '17 at 21:56
  • jfriend00: "An unfulfilled promise does not keep node.js alive by itself." now this can explain my confusion. – cYrus May 01 '17 at 22:01
  • @jfriend00 if you turn your comment into a proper answer I'll accept it. – cYrus May 01 '17 at 22:08

3 Answers3

4

An unfulfilled promise does not keep node.js alive by itself. It takes an underlying uncompleted async operation that is still alive (usually with some native code behind it) for node.js to automatically stay alive.

Examples of things that automatically keep node.js alive are open sockets, timers that haven't fired, etc...

An unfulfilled promise is just a Javascript object sitting in memory. It has no more effect on the lifetime of a node.js process than any other object in node.js. Keep in mind that a promise is JUST a notification scheme where you can register an interest in a resolve or reject event for a particular operation (kind of like an event emitter with special features). It's the underlying async operation (which is usually backed by native code that runs the async operation) which actually holds the process open. The promise itself doesn't affect the process itself at all.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • There's still something that I don't get... it's OK that an unfulfilled Promise is not enough to keep Node.js running but then what about the rest of the async function? Isn't that an underlying uncompleted async operation that is still alive? – cYrus May 02 '17 at 01:11
  • @cyrus - can you ask about a specific async operation? – jfriend00 May 02 '17 at 01:23
  • In each of the above two examples an `async` function is started and never completed, i.e., the code after the `await` is never executed because the runtime terminates. Isn't such code supposed to be eventually executed? – cYrus May 02 '17 at 01:44
  • @cyrus - only when the promise is resolved which may or may not happen. A promise can be such that it has no still running async operation associated with it like in your example and if nothing ever calls resolve or reject on it, then it never fulfills and can even be eligible for garbage collection. – jfriend00 May 02 '17 at 02:08
1

As far as I could understand your confusion here, the explanation is :

When you write an async function, it returns a promise which is not resolved as expression of await is never resolved and that promise is pending. Worth a readh : mdn doc for async

Now it won't block the main thread execution. What happens to the unresolved promises can be read here in one of the SO's answer : unresolved promises

Community
  • 1
  • 1
binariedMe
  • 4,309
  • 1
  • 18
  • 34
0

Your async function is just terminating immediately and returning you a promise. Try the following:

var myAsync = async function () {
    console.log("inside myAsync - before resolving");
    await new Promise(resolve => {
      setTimeout(() => {
        resolve();
      }, 1000);});
    console.log("inside myAsync - after resolving");
};

console.log("after declaring myAsync");
myAsync().then(() => {console.log("myAsync has resolved")});

If the setTimeout was set to infinite (or if you remove it altogether), you would get only "inside myAsync" followed by "after declaring myAsync". That's on purpose if you think about it, as the whole point of this mechanism is to prevent deadlocks after all.

Source: async function in MDN

Konamiman
  • 49,681
  • 17
  • 108
  • 138