likes
comments
collection
share

你知道吗?在try/catch块之外,return await是多余的

作者站长头像
站长
· 阅读数 15

今天在 CR 时候看到一个eslint提示

 你知道吗?在try/catch块之外,return await是多余的

出错信息是: Redundant use of await on a return value,本文举例子聊一下在编写异步函数时,await、return和return await之间存在差异

我们从这个异步函数开始:

async function waitAndMaybeReject() {
  // 等待一秒钟
  await new Promise((r) => setTimeout(r, 1000));
  // 抛硬币
  const isHeads = Boolean(Math.round(Math.random()));

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

这会返回一个Promise,等待一秒钟,然后具有50%的可能性用"yay"进行完成或用错误进行拒绝。让我们以几个微妙不同的方式使用它:

// 只是调用
async function foo() {
  try {
    waitAndMaybeReject();
  } catch (e) {
    return 'caught';
  }
}

这里,如果你调用foo,返回的 Promise 将始终以undefined进行完成,而不等待。

由于我们没有等待或返回waitAndMaybeReject()的结果,所以我们没有以任何方式对其进行反应。像这样的代码通常是一个错误。

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

这里,如果你调用foo,返回的Promise将始终等待一秒钟,然后要么以undefined进行完成,要么以"caught"进行完成。

因为我们等待waitAndMaybeReject()的结果,它的拒绝将被转换为抛出,我们的catch块将执行。然而,如果waitAndMaybeReject()完成,我们不会对值进行任何操作,不 return 结果。

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

这里,如果你调用foo,返回的Promise将始终等待一秒钟,然后要么以"yay"进行完成,要么以Error('Boo!')进行拒绝。

通过返回waitAndMaybeReject(),我们推迟到它的结果,因此我们的catch块永远不会运行。如果你不理解为什么为什么直接return waitAndMaybeReject(),到导致下面的 catch 抓不到东西,别着急,往下看。

你在try/catch块中想要的是return await:

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

这里,如果你调用foo,返回的Promise将始终等待一秒钟,然后要么以"yay"进行完成,要么以"caught"进行完成。

因为我们等待waitAndMaybeReject()的结果,它的拒绝将被转换为抛出,我们的catch块将执行。如果waitAndMaybeReject()完成,我们返回它的结果。

如果上面的内容看起来令人困惑,可能更容易将其视为两个分开的步骤:

    async function foo() {
      try {
        // 等待waitAndMaybeReject()的结果稳定下来,
        // 并将完成值分配给fulfilledValue:
        const fulfilledValue = await waitAndMaybeReject();
        // 如果waitAndMaybeReject()的结果拒绝,我们的代码
        // 抛出,我们跳到catch块。
        // 否则,这个块继续运行:
        return fulfilledValue;
      } catch (e) {
        return 'caught';
      }
    }


最后总结一下,在try catch内,允许 return await 这样的写法发生,因为catch需要捕获结果,但是如果不在 try catch内,写return await是多余的。