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?
Await is in an async function to ensure that all promises that are returned in the function are synchronized. With async/await, there's no use of callbacks. try and catch methods are also used to get rejection values of async functions.
Await expressions make promise-returning functions behave as though they're synchronous by suspending execution until the returned promise is fulfilled or rejected. The resolved value of the promise is treated as the return value of the await expression.
Synchronous code inside an async function runs synchronously. The interpreter will only move on to the next line after the call of the async function (here, the console. log("b"); ) after all synchronous code has finished - for example, if it runs into an await .
The differences between asynchronous and synchronous include: Async is multi-thread, which means operations or programs can run in parallel. Sync is single-thread, so only one operation or program will run at a time. Async is non-blocking, which means it will send multiple requests to a server.
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.
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)
})()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With