【问题标题】:Using await within a Promise在 Promise 中使用 await
【发布时间】:2018-01-03 01:47:58
【问题描述】:

将 Promise 的回调定义为异步似乎存在本质上的错误:

return new Promise(async (resolve, reject) => {
  const value = await somethingAsynchronous();
  if (value === something) {
    return resolve('It worked!');
  } else {
    return reject('Nope. Try again.');
  }
});

这显然是一个antipattern,并且有编码problems which can arise from it。我知道,即使将 await 语句放在 try/catch 块中,也更容易在此处捕获错误。

我的第一个问题是,当人们想要转发具有不同解析/拒绝值的 Promise 时,编写这样的代码的最佳方式是什么?用 then/catch?即

return new Promise((resolve, reject) => {
  somethingAsynchronous().then(value => {
    if (value === something) {
      return resolve('It worked!');
    } else {
      return reject('Nope. Try again.');
    }
  }); // errors would now be propagated up
});

还是按照here 的建议将其完全取出 Promise 构造函数?

async function outerFunction() {
  const value = await somethingAsynchronous();
  return new Promise((resolve, reject) => {
    if (value === something) {
      return resolve('It worked!');
    } else {
      return reject('Nope. Try again.');
    }
  });
}

但是,如果在 outerFunction() 中有多个 await 语句,即调用多个异步函数的线性代码块怎么办。那么您是否必须每次都创建并返回一个新的 Promise?

但是你如何解释这样的代码呢?

async function outerFunction() {
  if (someSynchronousCheck()) {
    return 'Nope. Try again.' // another reject case
  }

  const value = await somethingAsynchronous();
  // ...
}

我有一种感觉,我让这变得比它应该的更复杂。我试图避免嵌套回调/链接 then/catch 块,而不会在未来造成更多问题。

我的最后一个问题是,为什么传递给 Promise 的回调不是天生的 async?它已经封装在一个 Promise 中,并期望异步调用解析/拒绝函数。

【问题讨论】:

  • 始终牢记,基本上次需要new Promise 是如果您正在与使用回调的不同API 进行互操作。

标签: javascript asynchronous ecmascript-6 promise async-await


【解决方案1】:

你这样做:

async function outerFunction() {
  const value = await somethingAsynchronous();
  if (value === something) {
    return 'It Worked!';
  }
  throw Error('Nope. Try again.');
}

使用asyncouterFunction 的结果包装成一个Promise。

如果您希望包装承诺解决某些问题,只需从 async 函数中返回它。如果您希望拒绝包装承诺,请在 async 函数中抛出错误。

但是你如何解释这样的代码呢?

async function outerFunction() {
  if (someSynchronousCheck()) {
    throw Error('Nope. Try again.');
  }

  const value = await somethingAsynchronous();
  // ...
}

【讨论】:

  • 最后一段正是我需要的答案。我试图弄清楚如何从异步函数内部“拒绝”某些东西。
  • "使用异步将 outerFunction 的结果包装成一个 Promise。" -- 谢谢!
【解决方案2】:

new Promise(async (resolve, reject) => { ... }) 是相对较新的反模式。它会导致创建 2 个 promise 对象而不是 1 个,构造函数内部发生的未捕获错误无法被 try..catch 捕获并导致未处理的拒绝。

考虑到可以使用async..await 处理promise 异步代码,Promise 构造函数的当前用例是非promise 异步代码,例如:

new Promise(resolve => setTimeout(resolve, 1000))

Promise构造函数包含同步代码或涉及其他promise时,应使用async函数构造promise。直接替换为async IIFE:

return (async (resolve, reject) => {
  const value = await somethingAsynchronous();
  if (value === something) {
    return 'It worked!';
  } else {
    throw 'Nope. Try again.';
  }
})();

如果在与async 一起使用时仍然需要Promise 构造函数,则应将Promise 构造函数在层次结构中向下移动,这样它就不会包装任何async 函数。

我的最后一个问题是,为什么传递给 Promise 的回调本质上不是异步的?它已经封装在一个 Promise 中,并期望异步调用解析/拒绝函数。

async 函数不仅仅是一个异步执行的函数,它返回另一个应该被使用的承诺——或者至少用catch 处理。 Promise 不应该使用从构造函数返回的承诺。

构造函数可以在同一个tick上解析,不一定是异步的。

Promise.resolve(1);

类似于

Promise(resolve => resolve(1))

而不是

Promise(resolve => setTimeout(() => resolve(1)))

【讨论】:

    【解决方案3】:

    您也可以通过简单地自己链接承诺:

    return new Promise((resolve, reject) => {
      somethingAsynchronous().then((value) => {
          if (value === something) {
            return resolve('It worked!');
          } else {
            return reject('Nope. Try again.');
          }
      }, (error) => { reject(error); });
    });
    

    我已经使用了一段时间了,它非常适合我。

    【讨论】:

    • 抱歉,忘记从我从 op 复制的代码中删除 async。 (更新)
    猜你喜欢
    • 1970-01-01
    • 2021-05-13
    • 2019-10-20
    • 1970-01-01
    • 2018-05-16
    • 1970-01-01
    • 1970-01-01
    • 2019-04-30
    • 1970-01-01
    相关资源
    最近更新 更多