Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is async required to call await inside a JavaScript function body? [duplicate]

One has to use async keyword on the containing function to use the await inside the function body.

async function fetchMovies() {
  const response = await fetch('/movies');
  console.log(response);
}

fetchMovies();

The await is being used to block on completion of the asynchronous fetch() call. As can be seen in the code, the function fetchMovies() is not even returning any value. And even if it did, it would affect the way the return value is consumed by the caller, but why should it matter to the call to another asynchronous call from the function body?

My question is why is this required? Is there some good explaination of that? Is it related to the need for actual implementation of await and supporting it in older JavaScript versions?

I know iffi pattern is used be able to use await but does that change the semantics for the code that follows the iffi code block in any way?

(async () => {
  const response = await fetch('/movies');
  console.log(response);
})();

I am also aware of top level await being supported in modules.

May be I am missing something really obvious.

like image 295
Sandip Chitale Avatar asked Feb 09 '21 05:02

Sandip Chitale


People also ask

Why is async await needed in JavaScript?

await can be used on its own with JavaScript modules. Note: The purpose of async / await is to simplify the syntax necessary to consume promise-based APIs. The behavior of async / await is similar to combining generators and promises. Async functions always return a promise.

Why is async required?

“async” keyword needs to be updated in front of functions that contain ”await” keyword to notify that the result might be available after a certain delay since we are explicitly making the main thread wait until the promise has been resolved. Await and Async has introduced synchronous behavior to the Execution.

Is await required in async function?

There's no specific need to mark a function async unless you specifically need one of the benefits of an async function such as the ability to use await inside that function or the automatic error handling it provides.

What does async do in JavaScript?

Async functions will always return a value. Using async simply implies that a promise will be returned, and if a promise is not returned, JavaScript automatically wraps it in a resolved promise with its value. Running the above code gives the alert output as 27, it means that a promise was returned, otherwise the .

What is the difference between async and await in JavaScript?

So, async ensures that the function returns a promise, and wraps non-promises in it. Simple enough, right? But not only that. There’s another keyword, await, that works only inside async functions, and it’s pretty cool. The keyword await makes JavaScript wait until that promise settles and returns its result.

What is the use of await function in JavaScript?

Await function is used to wait for the promise. It could be used within the async block only. It makes the code wait until the promise returns a result. It only makes the async block wait. Notice that the console prints 2 before the “Hello World”. This is due to the usage of the await keyword.

What does the async keyword DO in JavaScript?

The async keyword tells the javascript engine that the function should return a promise, and any return statements in the function should resolve that promise. What happens if we modify it to cache the values so we don't always call the await?

How to use JavaScript async-await clause to handle promises in JavaScript?

How to use the JavaScript Async-Await clause to handle Promises in JavaScript? The await keyword waits for the script until the function settles its promise and returns the result. We can use the await keyword only inside the async functions. It will pause the “async” function and wait for the Promise to resolve before moving on.


Video Answer


3 Answers

There are three reasons the async keyword exists:

  1. In ECMAScript language versions prior to 2015, await was not a keyword. Marking a function async provides a syntactic "bailout" to indicate a breaking change in the language grammar within the body of the function.

    This is the most important reason. Without the async keyword, all programs written in ECMAScript 5 or older would no longer work if they used the await keyword as a variable (in fact this was done intentionally in some cases as a polyfill before async/await was standardized), since that would cause a breaking change without the addition of async to the specification. Because of this, async is syntactically necessary to avoid breaking changes to the language.

  2. It provides a convenient marker for parsers, avoiding an infinite look-ahead in order to determine whether or not a function is asynchronous.

    This makes parsing more efficient, which is appealing for both ECMAScript implementers and developers, though this reason alone does not make async strictly necessary to the syntax.

  3. async also performs its own transformation on the function, which is done regardless of whether or not the await keyword is present in the body.

    Consider the following two functions:

    function foo() {
      if (Math.random() < 0.5) {
        return 'return';
      } else {
        throw 'throw';
      }
    }
    
    async function bar() {
      if (Math.random() < 0.5) {
        return 'return';
      } else {
        throw 'throw';
      }
    }
    

    async performs the following transformation of function bar():

    function bar() {
      return new Promise((resolve, reject) => {
        try {
          resolve((/*async function bar*/() => {
            if (Math.random() < 0.5) {
              return 'return';
            } else {
              throw 'throw';
            }
          })());
        } catch (reason) {
          reject(reason);
        }
      });
    }
    

    Those familiar with promises will recognize that we can simplify the above since the Promise constructor executor function will implicitly reject if it throws an error synchronously:

    function bar() {
      return new Promise((resolve) => {
        if (Math.random() < 0.5) {
          return resolve('return');
        } else {
          throw 'throw';
        }
      });
    }
    
like image 190
Patrick Roberts Avatar answered Oct 21 '22 03:10

Patrick Roberts


I assume your exact question is this: "Handling return values (null or something) depends on the consumer who called the function. They "should" supposedly get it even if another asynchronous function is called in-between. So why does it matter to wait before further other asynchronous calls?"

You see, such fetch() calls are done in Databases within the duration of "initiating" and "closing" the connection. Almost every method used is asynchronous in this case. So while you're executing fetchMovies(); The thread might move further and execute connection.close(); before the fetching is resolved and returned.

The exact scenarios are like this:

await client.connect();  //connection establishment
// Your purposeful methods
async function fetchMovies() {
  const response = await fetch('/movies');
  console.log(response);
}

await fetchMovies();

// Closing connection to avoid attacks and maintain concurrency
await client.close();

If any method, in this case, is called in an asynchronous manner, the whole session of a Database connection is wasted and our function would return undefined or throw an error "Cannot use a session that has ended"

So we need to "wait" for the "Pending" Promises to reach a "Fulfilled" or "Rejected" state before executing further calls.

You can refer more to this article: Using Promises, async / await with MongoDB just for the sake of understanding.

like image 40
iGetRandomBugs Avatar answered Oct 21 '22 04:10

iGetRandomBugs


I think it's to make it clear that the function contains asynchronous code. Let's use another example that does return something:

async function canUseGeolocation() {
  const result = await navigator.permissions.query({name: 'geolocation'});
  return result.state;
}

The async keyword tells the javascript engine that the function should return a promise, and any return statements in the function should resolve that promise. What happens if we modify it to cache the values so we don't always call the await?

function canUseGeolocation() {
  if (cachedPermissionState) return cachedPermissionState;
  const result = await navigator.permissions.query({name: 'geolocation'});
  cachedPermissionState = result.state;
  return result.state;
}

How should javascript know that the function should return a promise? Because it contains an await? What if you later change the function so that the cachedPermissionState is set elsewhere and this function only returns that value so you remove the await? Should that first return statement return a promise or return the value? That would now change the whole way the function is executed and what is returned by return cachedPermissionState;. By using async, we can know that it really returns a promise that the return statement resolves without scanning the function for await statements to determine if it should be treated as async or not.

like image 2
Jason Goemaat Avatar answered Oct 21 '22 04:10

Jason Goemaat