Async, await and control flow

Sung
sung.io

Control flow when using async & await

Structure

  1. Look at code
  2. Fix it

Content

  1. Concurrency
  2. Inside a callback

await suspends the current async function, including all control structures.

async function httpGet(url) {
  const content = await fetch(url);

  console.log(content);
}

1. Concurrency

  1. Sequential
  2. Concurrent

Example 1

async function printData() {
  const res1 = await fetch('http://my.api/1');
  const res2 = await fetch('http://my.api/2');

  console.log(res1, res2);
}
async function printData() {
  const [res1, res2] = await Promise.all(
    fetch('http://my.api/1'),
    fetch('http://my.api/2')
  );

  console.log(res1, res2);
}

await - sequential

Promise.all() - concurrent;

Example 2

async function doWork() {
  const [res1, res2] = await Promise.all(
    httpPost('http://my.api/begin'),
    httpPost('http://my.api/finish')
  );

  console.log(res1, res2);
}
async function doWork() {
  const res1 =
    await httpPost('http://my.api/begin');
  const res2 =
    await httpPost('http://my.api/finish');

  console.log(res1, res2);
}

Example 3

async function attack(url) {
  while(true) {
    await fetch(url)
  }
}

await suspends the current async function, including all control structures.

async function attack(url) {
  while(true) {
    await fetch(url) //
  }
}
async function attack(url) { //
  while(true) {
    fetch(url)
  }
}
function attack(url) {
  while(true) {
    fetch(url)
  }
}

2. Inside a Callback

  1. forEach
  2. map

forEach

async function showData(urls) {
  urls.forEach(url => { //
    const data = await fetch(url);
    console.log(data);
  })
}
async function showData(urls) {
  urls.forEach(async (url) => { //
    const data = await fetch(url);
    console.log(data);
  })
}

forEach is synchronous but callback is asynchronous

async function showData(urls) {
  urls.forEach(async (url) => { //
    const data = await fetch(url);
    console.log(data);
  })
}
async function showData(urls) {
  for (url of urls) {
    const data = await fetch(url);
    console.log(data);
  }
}

Regular for-loop works too

async function showData(urls) {
  for (let i = 0; i < urls.length; i++) {
    const url = urls[i];
    const data = await fetch(url);
    console.log(data);
  }
}

Concurrent version

async function showData(urls) {
  for (url of urls) { //
    const data = await fetch(url);
    console.log(data);
  }
}

await - sequential

Promise.all() - concurrent

async function showData(urls) {
  const promises = urls.map(url => {
    return fetch(url);
  });

  await Promise.all(promises); //
}

return in async

An async function returns a promise 'p'

Return value

  • non-promise => 'p' resolves with it
  • promise => 'p' mirrors that promise
async function showData(urls) {
  const promises = urls.map(url => {
    return fetch(url);
  });

  await Promise.all(promises); //
}
async function showData(urls) {
  const promises = urls.map(url => {
    return fetch(url);
  });

  return await Promise.all(promises); //
}
return await Promise.all(promises);
  1. Unwraps Promise.all()
  2. Wraps again when return
async function showData(urls) { //
  const promises = urls.map(url => {
    return fetch(url);
  });

  return Promise.all(promises);
}
function showData(urls) {
  const promises = urls.map(url => {
    return fetch(url);
  });

  return Promise.all(promises);
}

map

async function getData(urls) {
  return urls.map(url => { //
    const content = await fetch(url);
    return content;
  })
}

map is synchronous but its callback is asynchronous

async function getData(urls) {
  return urls.map(async (url) => { //
    const content = await fetch(url);
    return content;
  })
}
async function getData(urls) {
  const promises = urls.map(async (url) => {
    const content = await fetch(url); //
    return content;
  });

  return await Promise.all(promises);
}
async function getData(urls) {
  const promises = urls.map(url => {
    return fetch(url);
  });

  return await Promise.all(promises); //
}
async function getData(urls) { //
  const promises = urls.map(url => {
    return fetch(url);
  });

  return Promise.all(promises);
}
function getData(urls) {
  const promises = urls.map(url => {
    return fetch(url);
  });

  return Promise.all(promises);
}

await suspends the current async function, including all control structures.

Use promsies if you need concurrency

Credit

End