Reputation: 1115
I imported a function from an internal utility library that I am unfamiliar with. There is no documentation for this library and I just assumed it was asynchronous due to its name getUserDetails
. I thought it was doing an http request.
I used it in an async function like this
async function getAllUserInfo(event) {
const details = await getUserDetails(event);
// other stuff
}
I was wrong in my assumption. A co-worker pointed out that is was not asynchronous. I ended up changing it, but when I was using it incorrectly it still worked. I was able to await a synchronous function and it returned the correct data.
My question is in regards to how it worked. Does prepending an await on a synchronous function make it resolve on the next tick, or does it return immediately like a synchronous function should?
Upvotes: 24
Views: 17632
Reputation: 88378
It worked because await
does not require its operand to be a promise! It returns the value of the awaited expression if it is not a promise.
See the documentation for the await operator
The important part is:
[rv] = await expression;
expression
: APromise
or any value to wait for.rv
: Returns the fulfilled value of the promise, or the value itself if it's not aPromise
.
In your case getUserDetails
did not return a promise, but rather some regular user details, so the await
expression just returned those details, just as if the operator was not there at all.
However, even though getUserDetails
is synchronous, preceding it with await
in your async function will give up control to its caller, and the "callback portion" after the await
is picked up later. Here is an example script:
function f() {
console.log('In f');
}
async function g() {
console.log('Starting g');
await f();
console.log('Finishing g');
}
console.log('Starting the script')
g();
console.log('Finishing the script')
Notice the output of the script:
$ node asynctest.js
Starting the script
Starting g
In f
Finishing the script
Finishing g
Notice how the await
call "paused" g, which was not able to resume until the main block finished! So the await
did have an effect. If you did not put the await there, then you would have seen "Finishing g" before "Finishing the script". Try it out!
BTW the reason for the effect is that even though await
can be given an expression that does not produce a promise, JS will turn a non-promise operand into a promise immediately resolved to that value. So a promise is still created and the part after await is treated as a callback, which cannot be run until the current execution flow finishes.
Upvotes: 63
Reputation: 6233
If you await a value that is not a promise, it is converted to a resolved promise by using Promise.resolve
.
function sync(){
return 1
}
(async ()=>{
const v = await sync(); console.log(v)
})();
(async ()=>{
const v = await Promise.resolve(sync()); console.log(v)
})()
Upvotes: 10