在大多数情况下,我认为我了解异步功能如何在JavaScript / Node.js中工作,并且我熟悉async
/ await
的语法。但这是一个非常具体的问题,我似乎在任何地方都找不到,而且我认为它涉及await
的内部工作,这超出了我的理解。
首先,我将以一个简单的示例开始,然后将其扩展为实际的工作代码。 (注意:我实际上是在使用Typescript,所以您会看到void
而不是undefined
,但这对问题并不重要。)
async function subtask() {
// doSomeStuff();
return; // returns a `Promise<void>`
}
// async function run() {
// see options below
// }
function app() {
run().catch((e) => console.error(e));
}
async function run() {
await subtask(); // resolves to `void`
return; // returns a new `Promise<void>`
}
async function run() {
return subtask(); // returns a new Promise, resolving to the `Promise<void>` of `subtask()`
}
在上面的简单示例中,我有一个异步函数run
,该函数调用了一个较小的异步函数subtask
。这两个函数都必须返回Promise<void>
。我有两个选择:(1)等待较小的函数并返回新的Promise<void>
,或(2)返回较小函数给出的包装承诺,稍后将解析为void
。
我对此工作缺乏了解。在选项1中,是否在subtask()
返回之前暂停执行?这实际上是什么意思?这是否意味着异步subtask
同步执行?这是否意味着调用app
的{{1}}也将暂停执行?如果run()
不同步怎么办?
是让承诺兑现起来并在以后解决,还是直接在app
函数中解决它,是“更好”的选择(表现更好)?
这很重要的原因是,在我的真实代码中,我有一堆较小的子任务,这些子任务都返回void,然后big函数也必须返回void-它不能返回数组。 (请注意,子任务无需按任何特定顺序运行。)
run
async function run() {
await Promise.all([
subtask0(),
subtask1(),
subtask2(),
]);
return;
}
async function run() {
return Promise.all([
subtask0(),
subtask1(),
subtask2(),
]).then((_all) => {});
}
答案 0 :(得分:2)
让Promise
冒出来总是更好。这样可以避免创建一个额外的Promise
对象,该对象也将等待着它(无论是否在幕后进行了优化,无论您使用的JavaScript引擎有待辩论)。
async function run() {
await subtask();
return;
}
这将创建一个额外的Promise
(随后将在链中执行一个额外的回调)。
async function run() {
return subtask();
}
这实际上并没有达到您的预期。这也会创建一个额外的Promise
(因为您使用的是async
关键字),并且在功能上与前面的示例几乎相同。通过使用async
关键字,您正在创建并返回一个新的Promise
,它将解析/拒绝与通过调用Promise
创建的subtask()
相同的值。如果删除async
关键字,则可以避免创建多余的Promise
。
现在有了您的Promise.all()
示例,我认为它们都是最佳的(假设您从第二个关键字中删除了不必要的async
关键字,如上所述)。第一个将创建2个Promise
(一个Promise.all()
,一个是从async
函数返回创建的),第二个也将创建(Promise.all()
一个,以及通过调用then()
创建的一个)。无论您要使用哪种,基本上都取决于个人选择。就我个人而言,我喜欢第二个示例,因为它没有将async
函数和Promise
s的使用混合在一起,我认为这使它更容易理解。
对于您的问题的最后一部分,将在await
关键字存在的位置(因此在run()
调用中)暂停执行。
从本质上讲,您还可以考虑使用await
关键字来转换代码:
// Do some stuff
let result = await run();
// Do some other stuff
对此:
// Do some stuff
run().then(result => {
// Do some other stuff
};
(await
的全部目的是减少由嵌套引起的混乱/复杂性)