Async await unexpectedly stops execution

Advertisements

I have two async functions in a module. Currently they are both just meant to wait, since the actual logic isn’t implemented yet.

Async module

export async function foo() {
  return new Promise(resolve => {
    setTimeout(() => {
       console.log('foo');
    }, 500);
  });
}

export async function bar() {
  return new Promise(resolve => {
    setTimeout(() => {
       console.log('bar');
    }, 500);
  });
}

In the main code, I am calling these two functions sequentially in another function. I want foo to finishe before bar starts, so I’m using await.

Main code

import { foo, bar } from './myModule'

async function submit() {
  await foo();
  await bar();

  // do other stuff
  otherStuff();
}

submit();

This code logs ‘foo’ but then stops working. It doesn’t call bar nor otherStuff. What am I doing wrong?

Additionally, according to this answer, async functions always return a Promise. I tried removing the Promise from foo and bar, since both are declared as async, but then all functions are called without waiting for the previous one to finish, i.e. await doesn’t have any effect at all.

>Solution :

When there are callbacks in your code – because of a library or the user of setTimeout() for example – you may be forced to create promises by hand.

In this case, what you did is correct, but you forgot to resolve those promises! Said differently: you promised something, but you didn’t keep your word.

Here is the working code:

export async function foo() {
  return new Promise(resolve => {
    setTimeout(() => {
       console.log('foo');
       resolve();
    }, 500);
  });
}

export async function bar() {
  return new Promise(resolve => {
    setTimeout(() => {
       console.log('bar');
       resolve();
    }, 500);
  });
}

Additionally, according to this answer, async functions always return a Promise. I tried removing the Promise from foo and bar, since both are declared as async, but then all functions are called without waiting for the previous one to finish, i.e. await doesn’t have any effect at all.

When the answer says "async functions always return a Promise", it’s because declaring a function as async will create a wrapper for you:

async function foo() {
  return 1;
}

is a sugar syntax for:

function foo(): Promise<number> {
  return Promise.resolve(1)
}

which works the same as:

function foo(): Promise<number> {
  return new Promise(resolve => {
    resolve(1)
  })
}

But since you are currently using setTimeout(), which uses a callback, this is not a promise. Something needs to be called back. So simply adding the sugar syntax async will not do what you intend.

For example, imagine you attempt to do this:

async function foo() {
  setTimeout(() => {
     console.log('foo');
  }, 500);
}

This will be equivalent to:

function foo(): Promise<ReturnType<typeof setTimeout>> {
  return Promise.resolve(
    setTimeout(() => {
       console.log('foo');
    }, 500);
  )
}

Which is not what you want.

Leave a ReplyCancel reply