-2

I have been reading up on async/await in Node.js. I have learnt that the await keyword waits for a promise to be resolved, or throws an exception if it was rejected.

I have also learnt that every function that wants to use await needs to be marked async. However, what does it mean for a function to be marked async?

All the resources and blog posts I was able to find seem to explain await in great detail, but ignore the concept of an async function, or briefly gloss over it. For instance, this author puts it like this:

This makes the function return a Promise implicitly.

What does the async keyword really do? What does it mean for a function to implicitly return a Promise? What are the side effects other than being able to use await?


Alright, so from the answers I have received so far it's clear that it simply wraps the function's return value into a Promise, much like Promise.then would. That just leaves a new question though. Why does a function that uses await need to be async and thus return a Promise?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jeroen
  • 15,257
  • 12
  • 59
  • 102
  • I don't understand what you don't understand. No matter what you actually return from your function, your async function will still return a Promise. If you return a number, it actually returns a Promise that resolves to the number. I'm having trouble trying to answer your question beyond that. – zero298 Apr 03 '18 at 17:59
  • @zero298 That would be a pretty good answer. In the question I asked what it means for it to implicitly return a `Promise`. From your comment, together with the other answers it seems like it just wraps your return value in a `Promise.resolve(return)`. I was also explicitly asking if there are any other side effects to using `async`, which appears to not be the case from your comment. – Jeroen Apr 03 '18 at 18:06
  • 2
    The question is quite unclear. You've provided what the async keyword does, and then asked what it does. We don't know exactly what you are missing. The [documentation on async/await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) has good examples. It's not quite clear what exactly about it you don't understand... which leads to answers that are just WAG's at what you don't understand. – Kevin B Apr 03 '18 at 18:18
  • @KevinB The MDN page indeed is much clearer than most resources I was able to find in a quick search online, which mostly leads to SO questions and blog posts. I was particularly interested in what the side effects are of adding `async` to a function. Saying it makes the function return a `Promise` is quite vague, and nothing online really expanded on what that means, but I also had no closure it would do other unexpected things. I'm still not quite sure why the async keyword would need to be a requirement to use `await`, if all that it does is wrap the function result into a promise. – Jeroen Apr 03 '18 at 18:24
  • 3
    well... `await`, just like `yield` in a generator, pauses the execution of that context until it is time for it to continue. that can't happen in a normal function, thus `async` is needed to signal that this is a function that will return a promise that will resolve once the function returns. If no await is used, the return happens synchronously, the promise is resolved, and any callbacks (or further awaits up the chain) will be ran on next tick. – Kevin B Apr 03 '18 at 18:26
  • @KevinB Feel free to post that as an answer. – Jeroen Apr 03 '18 at 18:28
  • Does this answer your question? [What are asynchronous functions in JavaScript? What is "async" and "await" in JavaScript?](https://stackoverflow.com/questions/62196932/what-are-asynchronous-functions-in-javascript-what-is-async-and-await-in-ja) – TylerH Jan 25 '23 at 17:25

3 Answers3

4

No matter what you actually return from your function, your async function will still return a Promise. If you return a Number, it actually returns a Promise that resolves to the Number your originally returned. This allows you to write synchronous "looking" code.

Rather than having to write out this:

function foo(){
    return Promise.resolve("foo");
}

You can just write this:

async function foo(){
    return "foo";
}

and foo() will automagically return a Promise that resolves to "foo".


In response to you comment:

Does it behave like Promise.then in the sense that if you already return a Promise, it won't wrap it again?

await will peel the Promise until it gets to a value:

async function foo() {
    return Promise.resolve(Promise.resolve(true));
}

async function bar() {
    return true;
}

(async function () {
    let tmp;
    tmp = await foo();
    console.log(tmp);
    tmp = await bar();
    console.log(tmp);
    console.log("Done");
}());

/*
Prints:

true
true
Done
*/

Why is async needed?

Paraphrasing from @KevinB's comment.

await, just like yield in a generator, pauses the execution of that context until the Promise it's waiting on is no longer pending. This cannot happen in normal functions.

If a function is async but does not contain an await, the promise will be resolved immediately, and any callbacks will be ran on the next tick.

Jeroen
  • 15,257
  • 12
  • 59
  • 102
zero298
  • 25,467
  • 10
  • 75
  • 100
  • Does it behave like `Promise.then` in the sense that if you already return a `Promise`, it won't wrap it again? – Jeroen Apr 03 '18 at 18:09
  • @JeroenBollen I haven't looked at the spec, so I'm not sure. – zero298 Apr 03 '18 at 18:10
  • Noticed the edit! Thanks! The question and all of its answers see to be attracting a fair bit of downvotes, so I am waiting a bit to see what that's all about before I pick an answer. – Jeroen Apr 03 '18 at 18:18
1

What does async do?

async is syntactic sugar for making your method chain Promise objects. Take the following method for example:

async function myFunction(a)
{
    if (a == 10) 
    {
        await otherFunction();
    }

    return 10;
}

The JavaScript runtime you use might make more optimized code, but in its simplest it will be something along the lines:

function myFunction(a) 
{
    if (a === 10) 
    {
        return otherFunction()
          .then(() => myFunction_continuation());
    }
    else 
    {
        return myFunction_continuation();
    }

    function myFunction_continuation() 
    {
        return Promise.resolve(10);
    }
}

For documentation on the Promise type I recommend checking out the Mozilla Developer Network page about the Promise type .

Why do you need to mark it async? Why not just use await?

Because your method needs to be split up into multiple "parts" for it to be able to have code execute after the method being awaited on. The example above has a single continuation, but there could be multiple.

The designers of JavaScript want to make it visible to the developer that the runtime is doing this "magic". But maybe the most important reason is that they don't want to break existing code using await as a variable name. They do this by making await a "contextual keyword". A "contextual keyword" is only a keyword in specific scenarios, in this case: when used inside a method marked as async:

function ABC() 
{
    var await = 10;
}

The above compiles. But if I add the async keyword to the function declaration it no longer does and throws an Uncaught SyntaxError: Unexpected reserved word.

Wazner
  • 2,962
  • 1
  • 18
  • 24
  • Maybe because I'm not chaining `then` calls? I wasn't sure which way would be easier to understand. – Wazner Apr 03 '18 at 18:18
  • I didn't end up marking this answer as the correct one because I am not sure how true it is that it uses the same back-end as a `Promise.then` uses. Still thanks though! – Jeroen Apr 03 '18 at 18:53
0

Asynchronous Task Running

The Basic idea is to use a function marked with async instead of a generator and use await instead of yield when calling a function, such as:

(async function() {
    let contents = await readFile('config.json');
    doSomethingWith(contents);
    console.log('Done');
});

The Async Keyword before function indicates that the function is meant to run in an asynchronous manner. The await keyword signals that the function call to readFile('config.json') should return a promise, and if it doesn't, the response should be wrapped in a promise.

The end result is that you can write asynchronous code as if it were synchronous without overhead of managing an iterator-based state machine.

  • Understanding ECMACSCRIPT 6 by Nicholas c. Zakas
  • While I didn't end up marking this answer as the "correct" one, I have a special appreciation for the comparison to generators. – Jeroen Apr 03 '18 at 18:52