JavaScript中的'return await promise'与'return promise'对比

199 阅读3分钟

JavaScript中的 "return await promise "与 "return promise "对比

当从一个异步函数中返回一个承诺时,你可以等待该承诺解决return await promise ,也可以直接返回return promise

async function func1() {
  const promise = asyncOperation();
  return await promise;
}
// vs
async function func2() {
  const promise = asyncOperation();
  return promise;
}

你很快就会看到,这两种表达方式确实有效。

然而,在某些情况下,这些表达式的行为是不同的吗?让我们来看看!

1.相同的行为

为了找出这两个表达式(return await promise vsreturn promise )之间的区别,我将使用一个辅助函数delayedDivide(n1, n2)

该函数对两个数字进行除法,并将除法结果用一个承诺包起来返回。

function promisedDivision(n1, n2) {
  if (n2 === 0) {
    return Promise.reject(new Error('Cannot divide by 0'));
  } else {
    return Promise.resolve(n1 / n2);
  }
}

如果第二个参数(除数)是0 ,该函数返回一个拒绝的承诺,因为被0 除去是不可能的。

好的,在定义了辅助函数后,让我们来除掉一些数字。

下面的函数divideWithAwait() 使用return await promisedDivision(6, 2) 表达式来返回6 除以2 的结果,该表达式被包裹在一个承诺中。

async function divideWithAwait() {
  return await promisedDivision(6, 2);
}
async function run() {
  const result = await divideWithAwait();
  console.log(result); // logs 3
}
run();

run() 函数中,await divideWithAwait() 表达式评估为除法结果3 。一切顺利。

现在让我们尝试使用第二个表达式,不使用await 关键字,并直接返回包裹除法结果的承诺return promisedDivision(6, 2)

async function divideWithoutAwait() {
  return promisedDivision(6, 2);
}
async function run() {
  const result = await divideWithoutAwait();
  console.log(result); // logs 3
}
run();

即使没有在divideWithoutAwait() 中使用await 关键字,在run() 函数中的表达式await divideWithoutAwait() 仍然正确地评估为6 / 2 除法结果3!

在这一步,你已经看到,使用return await promisereturn promise 并没有什么不同。至少在处理成功实现的承诺时是如此。

但是,让我们来搜索更多!

2.不同的行为

现在让我们采取另一种方法,特别是尝试处理被拒绝的许诺。为了使函数promisedDivision(n1, n2) 返回一个被拒绝的承诺,我们把第二个参数设置为0

因为promisedDivision(n1, 0) 现在会返回被拒绝的承诺,让我们也把调用包装成一个try {... } catch (error) {...} - 看看被拒绝的承诺是否被捕获。

好的,让我们使用return await promisedDivision(5, 0) 表达式和await 关键字。

async function divideWithAwait() {
  try {
    return await promisedDivision(5, 0);
  } catch (error) {
    // Rejection caught
    console.log(error); // logs Error('Cannot divide by 0')
  }
}
async function run() {
  const result = await divideWithAwait();
}
run();

因为除以0是不可能的,promisedDivision(5, 0) 返回一个拒绝的承诺。catch(error) { ... } 成功地捕获了由promisedDivision(5, 0) 抛出的被拒绝的承诺。

第二种方法,即省略了await ,又如何呢?

async function divideWithoutAwait() {
  try {
    return promisedDivision(5, 0);
  } catch (error) {
    // Rejection NOT caught
    console.log(error);
  }
}
async function run() {
  const result = await divideWithoutAwait();
}
run(); // Uncaught Error: Cannot divide by 0

然而这一次,catch(error) { ... } 没有捕捉到被拒绝的承诺。

现在你可以很容易地看到使用return await promisereturn promise 的主要区别。

当被包裹到try { ... } 中时,附近的catch(error) { ... } 只有在承诺被等待的情况下才会捕捉到被拒绝的promise (这对return await promise 也是如此)。

3.总结

在大多数情况下,尤其是在承诺成功解决的情况下,使用return await promisereturn promise 并没有很大的区别。

然而,如果你想捕捉从异步函数返回的被拒绝的承诺,那么你肯定应该使用return await promise 表达式,并特意添加await

catch(error) {...} 语句只抓取 语句中try {...} 等待的被拒绝的承诺。