【发布时间】:2017-04-06 07:44:48
【问题描述】:
我没有看到这些构造被大量使用,但我发现自己编写它们是为了在通常不会返回承诺的函数中使用 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 有什么不足之处?
【问题讨论】:
-
@DrewR 将返回值添加到当前不返回任何内容的函数不会违反任何替换原则。那么,为什么还要费心将所有内容都包装在另一层函数和缩进中呢?
-
那么,第一个代码示例实现了第二个没有实现的什么(除了引入一个新功能)?我的意思是,通常你可以在 IIFE 块中包装代码块,但通常人们根本没有理由不这样做。例如,有时是为了保护本地命名空间。这是做什么的?
-
@Pointy 为了使用'await'关键字,关键字出现的函数必须用'async'注释。 'async' 注释是'returns a promise' 的语法糖。由于调用回调的库没有预料到这一点,因此没有机会处理 Promise 可能抛出的任何错误(编辑 - 这是错误的,尝试...全部捕获)。此外,在这个特定函数中,需要立即增加
this.pendingMsgs(不要推迟到事件循环的某些后续迭代)——将回调声明为异步并不提供这样做的机会。 -
关于异常的要点是需要考虑的,但是在第二个示例中,
pendingMsgs的增量将与第一个示例同时发生。将async回调传递给的函数仍将被立即调用,并且该增量发生在任何异步操作开始之前。 -
@Pointy 考虑一下我可以将异步 fn 的全部内容包装在 try ... catch 中,如果我想在这种情况下处理错误,请确保不要重新抛出。所以那里没有问题。所以上面的例子在功能上等价于 when this.pendingMsgs++;被执行?我担心这里调用回调的问题,增量和后续代码被延迟,来自较早调用的较早承诺完成,递减pendingMsgs,观察它为零并在实际上有另一条消息时开始关闭资源马上处理。
标签: javascript async-await ecmascript-2017