Skip to content

Instantly share code, notes, and snippets.

@GeekTrainer
Last active February 14, 2021 14:24
Show Gist options
  • Save GeekTrainer/6af943150630754d95c3e6cba09c4172 to your computer and use it in GitHub Desktop.
Save GeekTrainer/6af943150630754d95c3e6cba09c4172 to your computer and use it in GitHub Desktop.
Async/await

Async/await

Let's consider the following code:

function getData() {
  $.get('https://jsonplaceholder.typicode.com/posts/1')
    .then((data) => {
      return data;
    });
}

let result = getData();
console.log(result);

We're using a promise and returning a value. The question is then what will be printed to the console. Have a guess?

Turns out, it's undefined.

Yup. Undefined.

That right there is one of the most confusing aspects of using promises. We're used to using return and having it return a value out of the function we've created. And, that's exactly what happened. The confusion is what function it actually returned from.

In our example, the value is returned from the delegate we've created. That value is not bubbled back up to the containing function (getData in our case). This makes creating helper functions like this a challenge at best.

And let's be honest. While promises are certainly cleaner than callbacks, there's still room for improvement. There's still a bit of nesting that's taking place, and it'd be nice if we could avoid that even still.

Enter async/await

Before we go any further, one thing we absolutely need to highlight is the fact that async/await is still very cutting edge. Many engines do not yet support the syntax. You will also find a good number of JavaScript developers are also unfamiliar with how async/await works, so you'll need to talk with your team and decide on a standard.

OK, now that we got that out of the way, let's talk about how to use async/await.

Async/await builds on promises. It's still the same concept - we call code that will be executing a long running operation, and we're handed back an IOU which guarantees our code will be executed when it completes. The difference is how we let the engine know what we want executed.

Let's start with a fundamental example, and then return to the problem posed at the beginning. Let's make a call, and then print the value.

function getData() {
  $.get('https://jsonplaceholder.typicode.com/posts/1')
    .then((data) => {
      console.log(data);
    });
}

getData();

We've seen this style of code before. We're going to stick with the same concept, only how we collect the value will change.

function async getData() {
  let data = await $.get('https://jsonplaceholder.typicode.com/posts/1');
  console.log(data);
}

getData();

Our updated getData is logically the same as the one we saw previously. They key is the await call. What await tells the runtime "Hey there! This call I'm about to make to get is going to take a few moments. Please don't shut things down, and put whatever the result of the function is and put it in the variable data." Pretty neat, huh?

A few quick notes

Without the call to await, get will return a Promise, which obviously isn't the data.

You'll also notice the async flag on the function. This is required, as it lets the runtime know an await will be coming at some point.

Tackling the return problem

Towards the beginning of this write-up we talked about the issue returning values when using promises. The delegate we pass into then is a function in and of itself, so when we call return, that function exits, but the return value isn't bubbled up. This can be rather confusing, and a challenge to deal with. The simplest solution? Async/await!

Important catch...

If you're going to be grabbing the value returned from a function using async/await, you must wrap that in an async function itself. Otherwise, you'll just get the promise back. I know, it's annoying and not the clearest bug.

Updating our code

Here's the original issue:

function getData() {
  $.get('https://jsonplaceholder.typicode.com/posts/1')
    .then((data) => {
      return data;
    });
}

let result = getData();
console.log(result);

Let's update that to use async/await

async function getData() {
  let data = await $.get('https://jsonplaceholder.typicode.com/posts/1');
  return data;
}

async function displayData() {
  let result = await getData();
  console.log(result);
}

displayData();

If you run the code you'll notice the result is properly displayed.

In review - when to use each?

You will find that many libraries support both callbacks and promises, and might be wondering which you should use. In my experience, most current development is done using promises, and it provides for cleaner code than callbacks.

As for promises versus async/await, that's very much dependent on the team. On my team, we lean heavily towards async/await. But I know many developers who I greatly respect who use promises. If you ask me - go with async/await. But, as I said up front, make sure your runtime supports the syntax (or use TypeScript).

Regardless of what you choose, be consistent, and communicate with your team!

Hope all of this helped! Feel free to reach out to me at @geektrainer if you have more questions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment