OverView of async/await

Targets of this article

  • People who know "Promise" of JavaScript.
  • People who want to know better way of writing async function than "Promise".

My experiences of "async/await"

I like "Promises" of JavaScript because we can write async function without Callback-Hell.

What if there is better writing style of async functions? That is async/await. Before I knew async/await, I had always used "Promises". But now, I prefer async/await to Promises. The reason why I prefer async/await is that we can write async functions as if syncronous functions. It is much readable and organized.

Why should we know this?

As I already told you, async/await allows us to write async functions that looks like syncronous style. I prepared example code below that is written Promises style and async/await style. Let's have a look.

// ### Promises style ###
function getFileDataByPromises() {
  return Promise.all([
    readFile('/path/to/file1.json'),
    readFile('/path/to/file2.json'),
    readFile('/path/to/file3.json'),
  ]).then(results => {
    const data1 = results[0];
    const data2 = results[1];
    const data3 = results[2];

    return buildDataWithFiles(data1, data2, data3);
  }).catch(err => {
    throw err;
  });
}


// ### async/await style ###
async function getFileDataByAsyncAwait() {
  const data1 = await readFile('/path/to/file1.json');
  const data2 = await readFile('/path/to/file2.json');
  const data3 = await readFile('/path/to/file3.json');

  try {
    return buildDataWithFiles(file1, file2, file3);
  } catch(err) {
    throw err;
  }
}


// ### Helper functions
const fs = require('fs');

function readFile(filePath) {
  return new Promise((resolve, reject) => {
    fs.readFile(filePath, 'utf-8', (err, data) => {
      if(err) {
        reject(err);
      }
      resolve(data);
    });
  });
}

function buildDataWithFiles(data1, data2, data3) {
  const buildData = [];

  // Something that combines file1, file2 and file3
  // ...

  return buildData;
}

How do you feel above code? Even though Promises pattern looks good in comparison to Callback-Hell pattern, async/await looks much better at least I think. In Promises, we have to pass result data via then method. If you want to add one more then method and pass first result of Promises again, You should write it like below.

function getFileDataByPromises() {
  let data1, data2, data3;
  return Promise.all([
    readFile('/path/to/file1.json'),
    readFile('/path/to/file2.json'),
    readFile('/path/to/file3.json'),
  ]).then(results => {
    data1 = results[0];
    data2 = results[1];
    data3 = results[2];

    return buildDataWithFiles(data1, data2, data3);
  }).then(builtData => {
    // something process with data1, data2 and data3.
    // ...
  }).catch(err => {
    throw err;
  });
}

In above example code, values are assigned to the empty variables(data1, data2 and data3). This means that this code potentially have bugs because values are mutable and It is possible that values might not be our expected value.

On the other hand, async/await style is much organized and stylish. We don't have to difine empty variable, which means we can use const declaration. We can avoid unnecessary updating values and bug generated by update.

How to use async/await

Syntax

async function asyncFunction() {
  const resultOfPromise = await somethingProcessWithPromise();
}

From MDN page of await.

The await operator is used to wait for a Promise. It can only be used inside an async function.

  • You can use await statement in functions with async declaration before function declaration.
  • When you put await operator before calling function, the function should return "promise" object.

Let's see the below image of example code. I wll explain what this code does after the image.

Example code

f:id:tsuyoshi4business:20171104185437p:plain

  1. Preparing functions.
    • async function asyncFunction() {...}
      • A function that use async/await
    • function somethingProcessWithPromise(){...}
      • A function that returns promise object.
  2. Calling asyncFunction()
    • Inside asyncFunction, I use await operator before "somethingProcessWithPromise()" that returns promise object.
    • resultOfPromise variable will be assigned value when resolve of promise is executed.
      • In this case resultOfPromise should be 'Hello!' because resolve function takes 'Hello' as a argument.
    • console.log is not exuecuted until the value is assigned to resultOfPromise variable.
    • resolve is executed after 1000 milliseconds with setTimeout.
  3. 'Hello!', 'Hi!' is output on the log.

Conclusion

  • We can write async functions as if syncronous functions.
  • To use async/await, we need to put async operator before function name and await operator before executing a function that returns promise object.
  • await operator can be inside only functions that is used async operator.

Resources