DEV Community

Discussion on: Explain async and await of Javascript like I am five.

Collapse
 
bhaibel profile image
Betsy Haibel

There are a few different angles I could take here!

Let's start with why they exist, follow up with what they do, and then go (briefly) into how they do it.

Why

All modern JavaScript runtimes (browser environments, Node.js, etc) use asynchronous I/O models. I/O operations (like calls to external APIs, or receiving user input) are characterized by waiting -- until your computer gets that API result, it can't do anything with it! Asynchronous I/O means that, while a function is "waiting" for an API result, the JavaScript runtime can start doing something else in the meantime. This improves app performance. But it's also harder to think about! We're taught how to program in a synchronous style, where line 1 executes, then line 2, then line 3. In an asynchronous style, maybe line 1 will execute, then line 6, then line 2....

There are a lot of different ways that JavaScript's language designers have tried to cope with this problem, like event emitters, callbacks, and promises. Async/await is the newest way of trying to make asynchronous code easier to think about.

What

Async/await looks like this:

function getBooksFromAPI() {
  return fetch(BOOK_API_ENDPOINT);
}

async function getBookTitles() {
  try {
    const bookData = await getBooksFromAPI();
  } catch {
    throw new Error("Book API unavailable");
  }
  return bookData.map(book => book.title);
}
Enter fullscreen mode Exit fullscreen mode

The first function returns a promise from fetch. This promise represents something the runtime intends to do -- it intends to get books from the API endpoint. Eventually, it will resolve to either success (book data) or failure. But it may or may not have done so yet. In the second function , we use the await keyword to wait for the promise to "fulfill". When the runtime hits an await, it knows to pause that function (and go do something else) until that promise has resolved itself.

When the promise resolves, the runtime "unpauses" the function. If the promise resolves with success, then the book data will get put into the bookData constant. If it fails, it'll throw a really non-specific error: Unhandled promise rejection. So we wrap it in a try/catch block to deal with that.*

  • try/catch isn't the only way to deal with Unhandled promise rejection errors. There are a lot of better ways! But it's the quickest to explain, and it's the most common.

Then, the runtime moves on to the next line, as though we were in synchronous code. In this case, we want to map the book data and return only the titles. Since await converted the API result promise (which isn't the API result, merely to the computer saying that it intends to get us an API result someday) into the actual book data, this is easy!

BUT! Because this function relies on awaiting something asynchronous (the API results) then it isn't going to return synchronously! So it needs to return a promise, too. The async keyword automatically wraps the return value of a function in a promise. If you're using await in a function, you need to mark it using the async keyword, so that the interpreter can trust that it returns a promise... because otherwise, you might try to call it synchronously and get unexpected results.

Ooof, that's a lot. and the how is even bigger.

How

This is something I don't really think can be done comprehensively in an ELI5 way. But the core of it is an idea called "generators," which let you specifically tell the JavaScript runtime "pause here until I call you next."

function * evenNumberGenerator() {
  const number = 0;
  while (true) {
    yield number;
    number = number + 2;
  }
}

const numbers = evenNumberGenerator();
const zero = numbers.next().value;
const two = numbers.next().value;
Enter fullscreen mode Exit fullscreen mode

Since we "pause" every time we hit the yield keyword, the infinite loop is "safe" -- we can "unpause" with next, and know that we'll get the next number in the sequence when we "pause" again. The await keyword uses generators under the hood to ask promises whether they've resolved yet, so that you can "unpause" the parent function and move on to the next line.

More

I've written up a brief, free email course that goes deeper into what all of the asynchronous "stuff" in Javascript does, the history of it, and how to use it effectively -- that might be a good next place to go, if this explanation was useful to you!

wecohere.com/products/untangling-a...

Collapse
 
rupeshiya profile image
Rupesh Krishna Jha

thanks a lot @Betsy . It's really awesome !!

Collapse
 
_darrenburns profile image
Darren Burns

This is a fantastic explanation!