til

How to unwrap promises from an array of promises

typescriptjavascript

There's a new method released in Safari 16.4 that allows to unwrap all promises from an array: Array.fromAsync.

I found and example from @mgechev:

async function* generate(total, throttle) {
  for (let i = 0; i < total; i++) {
    await new Promise((resolve) => setTimeout(resolve, throttle));
      yield i + 1;
  }
}

// [1, 2, 3, 4, 5]
console.log(await Array.fromAsync(generate(5, 200)));

As you can see it returns a Promise, so what happens when a promise is rejected? Yes, you have to handle it. In the next example, the error is caught and the expression of Array.fromAsync will return undefined. We could use ?? to return a fallback array:

async function withErrorExample() {
  const err = new Error();
  const badIterable = {
    [Symbol.iterator]() {
      throw err;
    }
  };

  // This returns a promise that will reject with `err`.
  const withErrorResult = await Array.fromAsync(badIterable)
    .catch((error) => {
      console.log("This is executed when there's an error.", error);
    }) ?? ["falback"];

  console.log("Result", withErrorResult);
}

withErrorExample();

As with Array.from there's also a second argument which is a map function:

class Array {
  static fromAsync(
    asyncItems: AsyncIterable | Iterable | ArrayLike,
    mapfn?: (value: any, index: number) => any,
    thisArg?: any
  ): Array;
}

I've made a CodeSandbox to play with it

I learnt this from @mgechev