await vs return vs return await

When writing async functions, there are differences between await
vs return
vs return await
, and picking the right one is important.

Let’s start with this async function:

async function waitAndMaybeReject() {
  // Wait one second
  await new Promise(r => setTimeout(r, 1000));
  // Toss a coin
  const isHeads = Boolean(Math.round(Math.random()));

  if (isHeads) return 'yay';
  throw Error('Boo!');
}

This returns a promise that waits a second, then has a 50/50 chance of fulfilling with "yay"
or rejecting with an error. Let’s use it in a few subtlety different ways:

Just calling

async function foo() {
  try {
    waitAndMaybeReject();
  }
  catch (e) {
    return 'caught';
  }
}

Here, if you call foo
, the returned promise will always fulfill with undefined, without waiting
.

Since we don’t await or return the result of waitAndMaybeReject()
, we don’t react to it in any way. Code like this is usually a mistake.

Awaiting

async function foo() {
  try {
    await waitAndMaybeReject();
  }
  catch (e) {
    return 'caught';
  }
}

Here, if you call foo
, the returned promise will always wait one second
, then either fulfill with undefined
, or
fulfill with "caught"

.

Because we await the result of waitAndMaybeReject()
, its rejection will be turned into a throw, and our catch block will execute. However, if waitAndMaybeReject()
fulfills, we don’t do anything with the value.

Returning

async function foo() {
  try {
    return waitAndMaybeReject();
  }
  catch (e) {
    return 'caught';
  }
}

Here, if you call foo
, the returned promise will always wait one second
, then either
fulfill with "yay"

, or
reject with Error('Boo!')

.

By returning waitAndMaybeReject()
, we’re deferring to its result, so our catch block never runs.

Return-awaiting

The thing you want in try/catch blocks, is return await
:

async function foo() {
  try {
    return await waitAndMaybeReject();
  }
  catch (e) {
    return 'caught';
  }
}

Here, if you call foo
, the returned promise will always wait one second
, then either
fulfill with "yay"

, or
fulfill with "caught"

.

Because we await the result of waitAndMaybeReject()
, its rejection will be turned into a throw, and our catch block will execute. If waitAndMaybeReject()
fulfills, we return its result.

If the above seems confusing, it might be easier to think of it as two separate steps:

async function foo() {
  try {
    // Wait for the result of waitAndMaybeReject() to settle,
    // and assign the fulfilled value to fulfilledValue:
    const fulfilledValue = await waitAndMaybeReject();
    // If the result of waitAndMaybeReject() rejects, our code
    // throws, and we jump to the catch block.
    // Otherwise, this block continues to run:
    return fulfilledValue;
  }
  catch (e) {
    return 'caught';
  }
}

Note: Outside of try/catch blocks, return await
is redundant. There’s even an ESLint rule to detect it
, but it allows it in try/catch.

Front-end Front稿源:Front-end Front (源链) | 关于 | 阅读提示

本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 综合技术 » await vs return vs return await

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录