2

I thought I understood how to use async and await till I saw the below code snippet.

So there is an onInput event handler function attached to the movie input textbox. Within it is called the fetchData asynchronous function which uses the await keyword to wait for results from the axios.get function.

My question is, why do we need to make the onInput function also async? I mean, the fetchData function is async. Which means, it will wait till the axios.get is resolved and the execution will be paused till axios.get is resolved. So when the line const movies = fetchData(event.target.value); executes, the fetchData function will be executed which will pause on the await axios.get statement. So why do we need to use await while calling fetchData and make onInput async??

const fetchData = async(searchTerm)=>{
    const results =  await axios.get('http://www.omdbapi.com/', {
    params:{
        apikey:'d9835cc5',
        s: searchTerm
        }

    });
    return results.data.Search;
}

    const movieInput = document.querySelector('input');
    
    
    const onInput = async event => {
        const movies = await fetchData(event.target.value);
        console.log(movies);
    }
    
    movieInput.addEventListener('input', onInput);

3 Answers 3

3

I mean, the fetchData function is async. Which means, it will wait till the axios.get is resolved and the execution will be paused till axios.get is resolved.

This concept is hiding a lot of detail that may be confusing, such as that paused execution is resumed using callback functions.

  • async functions do not pause execution of their callers.

    Instead they return a promise that will be resolved with the value syntactically returned from executing the async function body. To be clear, the value apparently returned from within an async function body is not returned to the caller directly - the caller gets a promise for it.

  • When executed the await operator sets up call backs for when its operand promise becomes settled. Effectively it calls the then method of its promise operand to supply a set of onfulfilled and onrejected callbacks, before storing the current execution context in memory and returning to the event loop.

    When it receives a callback from promise settlement, the await operator restores the execution context it previously saved. If the awaited promise is rejected, await throws the rejection reason. If fulfilled, await resumes exection and returns the fulfilled value of the promise as the result of executing the await operator.

Now historically await was never a reserved keyword - not mentioned in ES3, future reserved keyword in ES6 (ECMAScript 2015) but reserved word in the current draft of ECMAscript as at May 2021.

Hence, to retain compatibility with code on the web, await was only recognized as an operator if it occurs within an async function - leaving it available as an identifier outside of async function bodies.

Likewise the async keyword was not historically reserved, but was able to be introduced without comparability issues by requiring its usage in a position that would have produced an unexpected identifier error in previous versions of JavaScript. Meaning before the function keyword or before an arrow function expression.

Finally you need to declare onInput as an async function because await is being used as an operator within its body. Without the async declaraton, await will be treated as an identifier rather than the name of an operator.

As a side note, the promise returned by onInput is being discarded and could generate an uncaught promise rejection error in its current form.


To answer the slightly different question of "why does await need to be used in the onInput function at all?", the value returned from fetchData is a pending promise. In order to set movies to the results.data.Search value obtained within fetchData, you need to wait for the fulfilled value of the returned promise. Using async/await is one means of doing so. The other is to add a fulfillment handler to the promise returned from fetchData by calling its then method.

Sign up to request clarification or add additional context in comments.

7 Comments

I think the async token was never thought of as a compatibility solution. Even if it wasn't necessary, it's still a good idea.
@Bergi I've made parts of the answer more direct. Checking in Firefox showed that async and await can still be used as identifiers outside of an async function to this day. Certainly agree that using async before an asynchronous function declaration is a good idea, not to mention it creates an AsyncFuntion object instead of a Function object!
@traktor would execution of the oninput function be paused on the line "const movies = await fetchData(event.target.value);"? I am understanding that it should pause and wait for the promise to resolve. Is that correct?
@theju112t JavaScript is single threaded - when called from the event loop task manager, script code continues until it returns to the task manager. The await operator in onInput stores the current execution environment and returns to the event loop, enabling other event driven JavaScript to be called and run from the event loop. Evaluation of the await operator expression within onInput resumes when one of the handlers added to the fetchData()...) promise is called. Call it "paused" if you like, but thinking of it as "suspended until something happens" may be clearer.
Seems like the async await implementation duplicates an entire set of function/methods which are nearly identical. I wonder if the same synch and async function can serve both roles. Perhaps, using special scoping or by leveraging the existing generics infrastructure.
|
1

You are using the await operator inside inInput. It's a JavaScript rule that functions using await must be async, so inInput must also be async. Have a look at this answer: https://stackoverflow.com/a/56685416/13357440

Also, MDN has useful information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

6 Comments

Ya I understand that part.. await can be used only inside an async function. My question is, why do we need to make onInput async at all? Isnt it enough that fetchData is async and it awaits on a particular line?
@theju112t - you don't, it could easily be written: const onInput = event => fetchOptions(event.target.value) and the end result would be the exact same, a promise is returned. Some people like the annotation of async so you can tell at a glance that a function returns a promise, but it's personal preference at that point.
@theju112t If you didn't need the result of that call to fetchData, you could make onInput not async and omit the await, but you want the return value from fetchData so you need to use await. stackoverflow.com/questions/59953976/…
@atultw - but you want the return value from fetchData so you need to use await - this is wrong. onInput returns the exact same promise regardless of using await or not.
@Adam ya but I dont want the promise as the return value. I want the actual data after the promise is resolved.
|
0

In general, you would want API calls to execute while the rest of your program runs, so the onInput would be async. Furthermore, javascript mandates that an await is inside of an async function, so the code was simply following its standards and rules as well. Typically, once the top level is an async, everything inside of it is just following the structure. More info can be found here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.