在 new Promise() 构造函数中使用 async/await 是一种反模式吗?

新手上路,请多包涵

我正在使用 async.eachLimit 函数来控制一次的最大操作数。

 const { eachLimit } = require("async");

function myFunction() {
 return new Promise(async (resolve, reject) => {
   eachLimit((await getAsyncArray), 500, (item, callback) => {
     // do other things that use native promises.
   }, (error) => {
     if (error) return reject(error);
     // resolve here passing the next value.
   });
 });
}

如您所见,我无法将 myFunction 函数声明为异步函数,因为我无权访问 eachLimit 函数的第二个回调中的值。

原文由 user5487299 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 403
2 个回答

您在 promise 构造函数执行器函数中有效地使用了 promises,因此这是 Promise constructor anti-pattern

您的代码是主要风险的一个很好的例子:不安全地传播所有错误。阅读为什么 在那里

此外,使用 async / await 可以使相同的陷阱更加令人惊讶。相比:

 let p = new Promise(resolve => {
  ""(); // TypeError
  resolve();
});

(async () => {
  await p;
})().catch(e => console.log("Caught: " + e)); // Catches it.

用一个天真的(错误的) async 等价:

 let p = new Promise(async resolve => {
  ""(); // TypeError
  resolve();
});

(async () => {
  await p;
})().catch(e => console.log("Caught: " + e)); // Doesn't catch it!

在浏览器的 Web 控制台中查找最后一个。

第一个之所以有效,是因为 Promise 构造函数执行程序函数中的任何 直接 异常都会方便地拒绝新构造的 promise(但在任何 .then 你自己)。

第二个不起作用,因为 async 函数中的任何直接异常都会拒绝 _async 函数本身返回的隐式承诺_。

由于 promise 构造函数执行器函数的返回值未被使用,这是个坏消息!

你的代码

没有理由不能将 myFunction 定义为 async

 async function myFunction() {
  let array = await getAsyncArray();
  return new Promise((resolve, reject) => {
    eachLimit(array, 500, (item, callback) => {
      // do other things that use native promises.
    }, error => {
      if (error) return reject(error);
      // resolve here passing the next value.
    });
  });
}

尽管为什么在拥有 await 时使用过时的并发控制库?

原文由 jib 发布,翻译遵循 CC BY-SA 3.0 许可协议

我同意上面给出的答案,但有时在你的承诺中使用异步会更整洁,特别是如果你想链接多个返回承诺的操作并避免 then().then() 地狱。在那种情况下我会考虑使用这样的东西:

 const operation1 = Promise.resolve(5)
const operation2 = Promise.resolve(15)
const publishResult = () => Promise.reject(`Can't publish`)

let p = new Promise((resolve, reject) => {
  (async () => {
    try {
      const op1 = await operation1;
      const op2 = await operation2;

      if (op2 == null) {
         throw new Error('Validation error');
      }

      const res = op1 + op2;
      const result = await publishResult(res);
      resolve(result)
    } catch (err) {
      reject(err)
    }
  })()
});

(async () => {
  await p;
})().catch(e => console.log("Caught: " + e));

  1. 传递给 Promise 构造函数的函数不是异步的,因此 linters 不会显示错误。
  2. 可以使用 await 按顺序调用所有异步函数。
  3. 可以添加自定义错误来验证异步操作的结果
  4. 错误最终被很好地捕获了。

但缺点是您必须记住放置 try/catch 并将其附加到 reject

原文由 Vladyslav Zavalykhatko 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题