简体   繁体   中英

Does async tag wrap a JavaScript function with a Promise?

So I understand that "async" ensures that a function will return a Promise, and if it doesn't then it wraps it in a promise.

My question is, if the function is already returning a Promise, does "async" wrap it in another Promise?

async function, return non-Promise:

async function foo() {
    return 5;
}

console.log(foo()) // Promise { 5 }

regular function, return Promise:

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

console.log(foo()) // Promise { 5 }

async function, return Promise:

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

console.log(foo()) // Promise { <pending> }

Why does the last one return "Promise { pending }" ? My intuition tells me the redundant "async" tag is wrapping the already returned Promise with another Promise. Is this correct?

If an async function returns a Promise, then the Promise returned by that function will resolve to the same value as the original Promise. This can be seen with a simple example:

async function foo() {
  return Promise.resolve(42);
}
console.log(await foo()); // "42", not "Promise { 42 }"

So in most normal situations, we can simply imagine that the Promise returned by the code inside the async function body is returned without being touched. But as you've stumbled across, even though the Promise returned by an async function will resolve to the same value as a Promise returned by the code, the actual Promise object is not necessarily the same:

let p1;
async function foo() {
  p1 = Promise.resolve(42);
  return p1;
}
let p2 = foo();
console.log('p1 === p2 ?', p1 === p2); // "false" (!)

So we can see that the Promise object returned by the function invocation is actually different from the Promise object that the function body returned. No matter, though, it will give the same result when we await it (or use Promise.then() ):

let p1;
async function foo() {
    p1 = Promise.resolve(42);
    return p1;
}
let p2 = foo();

console.log(await p1); // '42'
console.log(await p2); // also '42'

(Note that to run these examples in eg a node repl shell, you'll need to wrap them like:

async function main() {
  /* code using async / await here */
}
main();

You need to call your last function as:

foo.then(function(r){console.log(r)});

The reason being, an async function needs to return a promise. A promise will log pending until the result is resolved. To capture the promise, you must call "then".

Here is a link for more info about then: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

Here is a link for more info about async functinos: https://fmpapidev.holstein.ca/swagger/index.html

Now I'm not certain what the native implementation of async / await is for modern node apps but if you take a look at what Babel generates when it transpiles to node 6

Take this simple async function:

async function fooAsync() {
  return 1;
}

Babel transforms this code to look like this:

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }

function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }

function fooAsync() {
  return _fooAsync.apply(this, arguments);
}

function _fooAsync() {
  _fooAsync = _asyncToGenerator(function* () {
    return 1;
  });
  return _fooAsync.apply(this, arguments);
}

You can see the transformation of your async method and the state machine it generates. The interesting part is that the generator, when executed, return a new Promise() . So to answer your question, just having the keyword async in your function, would make it return a Promise . This can also be seen in Typescript where the compiler will moan if you have an async method and you don't specify a return type of Promise<T>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM