退还未决的承诺有实际的好处吗?

时间:2018-10-03 19:03:12

标签: javascript node.js asynchronous async-await

在大多数情况下,我认为我了解异步功能如何在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)返回较小函数给出的包装承诺,稍后将解析为void

我对此工作缺乏了解。在选项1中,是否在subtask()返回之前暂停执行?这实际上是什么意思?这是否意味着异步subtask同步执行?这是否意味着调用app的{​​{1}}也将暂停执行?如果run()不同步怎么办?

是让承诺兑现起来并在以后解决,还是直接在app函数中解决它,是“更好”的选择(表现更好)?

这很重要的原因是,在我的真实代码中,我有一堆较小的子任务,这些子任务都返回void,然后big函数也必须返回void-它不能返回数组。 (请注意,子任务无需按任何特定顺序运行。)

选项1

run

选项2

async function run() {
    await Promise.all([
        subtask0(),
        subtask1(),
        subtask2(),
    ]);
    return;
}

async function run() {
    return Promise.all([
        subtask0(),
        subtask1(),
        subtask2(),
    ]).then((_all) => {});
}

1 个答案:

答案 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的全部目的是减少由嵌套引起的混乱/复杂性)