简体   繁体   中英

Does awaiting a synchronous function synchronously return a value?

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?

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 : A Promise or any value to wait for.
  • rv : Returns the fulfilled value of the promise, or the value itself if it's not a Promise .

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) })()

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