在很大程度上,我认为我了解异步函数在 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));
}
选项 1
async function run() {
await subtask(); // resolves to `void`
return; // returns a new `Promise<void>`
}
选项 2
async function run() {
return subtask(); // returns a new Promise, resolving to the `Promise<void>` of `subtask()`
}
在上面的简单示例中,我有一个异步函数 run
调用较小的异步函数 subtask
。两个函数都必须返回 Promise<void>
。我有两个选择:(1)等待较小的函数并返回一个新的 Promise<void>
,或 (2) 返回由较小函数给出的包装 promise ,稍后将解析为 void
.
我对它的工作原理缺乏了解。在选项 1 中,执行是否在 subtask()
之前暂停。返回?这实际上意味着什么?这是否意味着异步 subtask
同步执行?这是否意味着app
,调用run()
,也会暂停执行吗?如果 app
会怎么样?是异步的,这会有所不同吗?
让 Promise 冒泡并稍后解决,还是直接在 run
内解决它“更好”(性能更高)吗?功能?
这很重要的原因是,在我的实际代码中,我有一堆较小的子任务,它们都返回 void,然后大函数也必须返回 void - 它不能返回数组。 (请注意,子任务不需要按任何特定顺序运行。)
选项 1
async function run() {
await Promise.all([
subtask0(),
subtask1(),
subtask2(),
]);
return;
}
选项 2
async function run() {
return Promise.all([
subtask0(),
subtask1(),
subtask2(),
]).then((_all) => {});
}
<小时/>
function app() {
// do some stuff
run(); // if `run` contains `await`, does execution pause here?
// what if `app` was async?
// do some more stuff
}
最佳答案
让 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
,我认为这更容易理解。
对于问题的最后一部分,只要存在 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
的全部目的是减少嵌套引起的困惑/复杂性)
关于javascript - 返回未决的 promise 有实际好处吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52634031/