ES8 立即调用异步函数表达式

IT技术 javascript async-await ecmascript-2017
2021-03-15 07:13:30

我还没有看到这些结构被大量使用,但我发现自己编写它们是为了在通常不会返回Promise的函数中使用 async/await,例如

chan.consume(queue, (msg) => {
  this.pendingMsgs++; // executed immediately
  (async () => {
    await this.handleMessage(msg);
    this.pendingMsgs--;
    if (cancelled && this.pendingMsgs === 0) {
       await chan.close();
       await this.amqpConnectionPool.release(conn);
    } 
  })();
});

chan.consume(queue, async (msg) => { // external lib does not expect a return value from this callback
  this.pendingMsgs++;  // executed in promise context(?)
  await this.handleMessage(msg);
  this.pendingMsgs--;
    if (cancelled && this.pendingMsgs === 0) {
       await chan.close();
       await this.amqpConnectionPool.release(conn);
    }
});

或者

chan.consume(queue, (msg) => {
  this.pendingMsgs++;  // no await - excess function decls & nesting
  this.handleMessage(msg).then(() => {
    this.pendingMsgs--;
    if (cancelled && this.pendingMsgs === 0) {
       chan.close().then(() => {
         this.amqpConnectionPool.release(conn);
       });
    }
  });
});

这是“一件事”吗?这里有我应该注意的陷阱吗?在这种情况下使用 async/await 的缺点是什么?

2个回答

这是“一件事”吗?

是的。它时不时地出现,例如这里它们被称为 IIAFEs :-)
如果你想把注意力集中在箭头上,你也可以称它们为 IIAAFs。

这里有我应该注意的陷阱吗?

每当你调用一个返回Promise的函数并且不将结果返回到其他地方时,你自己负责Promise - 这意味着你必须处理它的错误。所以模式通常应该看起来像

(async () => {
    …
})().catch(err => {
    console.error(err);
});

如果您不想担心未处理的拒绝事件。

在这种情况下使用async/ 的秘诀是什么await

then版本相比,不多但是,您说“外部库不期望此回调的返回值”,这可能暗示库与异步回调不兼容,因此请注意您在做什么时。它也可能取决于从回调同步抛出的异常,所以这完全取决于库在这里的期望(如果没有期望,将来是否会改变)。您不希望将来出现不兼容,以防库开始特别处理 promise 返回值。

但是,我仍然推荐第二种模式,它直接将async函数作为回调直接传递,因为它具有更好的可读性。如果您想避免向库返回Promise,请创建一个包装回调的辅助函数:

function toVoid(fn) {
    return (...args) => void fn(...args);
}
function promiseToVoid(fn) {
    return (...args) => void fn(...args).catch(console.error);
}

你可以这样使用:

chan.consume(queue, toVoid(async (msg) => {
     … // use `await` freely
}));
我喜欢包装函数的想法。谢谢。
2021-04-25 07:13:30
对有关未处理的Promise拒绝的注释非常赞赏——这是一个很好的答案。异步口袋函数现在开始出现在很多文档中,很多人都忽略了在将一个函数插入非异步函数时可能发生的错误。我还要说值得指出的.catch()是,只有在您不使用await. 即运行await (async()=>{})();很好,无需添加.catch(). 但是如果你离开await了,那么你必须记住.catch()在最后锁定。
2021-04-27 07:13:30
@chbchb55 主要是因为try/catch需要额外的缩进级别,而我不喜欢那样。特别是当这catch是事后的想法并且与真正的控制流无关时。此外,在async function外可能发生异常try- 使用内置错误处理我们可以处理它们。最后但并非最不重要的.catch()是更短:-)
2021-05-08 07:13:30
.catch()async函数允许你try { } catch (error) { }在它们内部说的时候,你为什么要使用
2021-05-10 07:13:30
(async () => {
        await func();
    })();