async/await implicitly returns promise?
The return value will always be a promise. If you don't explicitly return a promise, the value you return will automatically be wrapped in a promise.
async function increment(num) { return num + 1;}// Even though you returned a number, the value is// automatically wrapped in a promise, so we call// `then` on it to access the returned value.//// Logs: 4increment(3).then(num => console.log(num));
Same thing even if there's no return! (Promise { undefined }
is returned)
async function increment(num) {}
Same thing even if there's an await
.
function defer(callback) { return new Promise(function(resolve) { setTimeout(function() { resolve(callback()); }, 1000); });}async function incrementTwice(num) { const numPlus1 = await defer(() => num + 1); return numPlus1 + 1;}// Logs: 5incrementTwice(3).then(num => console.log(num));
Promises auto-unwrap, so if you do return a promise for a value from within an async
function, you will receive a promise for the value (not a promise for a promise for the value).
function defer(callback) { return new Promise(function(resolve) { setTimeout(function() { resolve(callback()); }, 1000); });}async function increment(num) { // It doesn't matter whether you put an `await` here. return defer(() => num + 1);}// Logs: 4increment(3).then(num => console.log(num));
In my synopsis the behavior is indeed inconsistent with traditionalreturn statements. It appears that when you explicitly return anon-promise value from an async function, it will force wrap it in apromise. I don't have a big problem with it, but it does defy normalJS.
ES6 has functions which don't return exactly the same value as the return
. These functions are called generators.
function* foo() { return 'test';}// Logs an object.console.log(foo());// Logs 'test'.console.log(foo().next().value);
I took a look at the spec and found the following information. The short version is that an async function
desugars to a generator which yields Promise
s. So, yes, async functions return promises.
According to the tc39 spec, the following is true:
async function <name>?<argumentlist><body>
Desugars to:
function <name>?<argumentlist>{ return spawn(function*() <body>, this); }
Where spawn
"is a call to the following algorithm":
function spawn(genF, self) { return new Promise(function(resolve, reject) { var gen = genF.call(self); function step(nextF) { var next; try { next = nextF(); } catch(e) { // finished with failure, reject the promise reject(e); return; } if(next.done) { // finished with success, resolve the promise resolve(next.value); return; } // not finished, chain off the yielded promise and `step` again Promise.resolve(next.value).then(function(v) { step(function() { return gen.next(v); }); }, function(e) { step(function() { return gen.throw(e); }); }); } step(function() { return gen.next(undefined); }); });}
Your question is: If I create an async
function should it return a promise or not? Answer: just do whatever you want and Javascript will fix it for you.
Suppose doSomethingAsync
is a function that returns a promise. Then
async function getVal(){ return await doSomethingAsync();}
is exactly the same as
async function getVal(){ return doSomethingAsync();}
You probably are thinking "WTF, how can these be the same?" and you are right. The async
will magically wrap a value with a Promise if necessary.
Even stranger, the doSomethingAsync
can be written to sometimes return a promise and sometimes NOT return a promise. Still both functions are exactly the same, because the await
is also magic. It will unwrap a Promise if necessary but it will have no effect on things that are not Promises.