Javascript 省略';等待&x27;在某些情况下?

Javascript 省略';等待&x27;在某些情况下?,javascript,async-await,es6-promise,Javascript,Async Await,Es6 Promise,我在代码中的几个地方使用了async/wait 例如,如果我有此功能: async function func(x) { ... return y; } async function func() { const foo = await tediousLongProcess("foo") // wait until promise is resolved const bar = await tediousLongProcess("bar") // wait un

我在代码中的几个地方使用了
async
/
wait

例如,如果我有此功能:

async function func(x) {
    ...
    return y;
}
async function func() {
    const foo = await tediousLongProcess("foo") // wait until promise is resolved
    const bar = await tediousLongProcess("bar") // wait until promise is resolved

    return Promise.resolve([foo, bar]) // Now the Promise of `func` is marked as a success. Keep in mind that `Promise.resolve` is not necessary, `return [foo, bar]` suffices. And also keep in mind that an async function *always* returns a Promise.
}
然后我总是这样称呼它:

async function func2(x) {
    let y = await func(x);
    ...
}
我注意到,在某些情况下,我可以省略
await
,程序仍将正确运行,因此我无法完全确定何时必须使用
await
,何时可以删除它

我的结论是,仅在return语句中直接删除
wait
是“合法的”

例如:

async function func2(x) {
    ...
    return func(x); // instead of return await func(x);
}
这个结论正确吗?或者,我在这里遗漏了什么

编辑:

下面的回答中没有提到的一个小(但重要)概念,我刚刚遇到并意识到:

如果被调用函数可能抛出异常,并且该语句因此在
try
块内执行,则在
return
语句中删除
wait
是不“合法的”

例如,删除下面代码中的
wait
“危险”:


原因是
try
块完成时没有异常,
Promise
对象返回“正常”。但是,在调用外部函数的任何函数中,当“执行”此
Promise
对象时,将发生实际错误并引发异常。只有在使用了
wait
时,才能在外部函数中成功处理此异常。否则,这个责任就增加了,需要额外的
try
/
catch
子句。

如果
func
是一个异步函数,那么使用和不使用
wait
调用它会产生不同的效果

async function func(x) {
  return x;
}

let y = await func(1); // 1
let z = func(1) // Promise (resolves to 1)
省略
await
关键字始终是合理的,但这意味着您将不得不以传统的方式处理承诺(首先要克服异步/await这一点)


如果您的返回语句使用了
wait
,那么您可以确定,如果它抛出错误,它可以在您的函数中被捕获,而不是被调用它的代码捕获。

我在上面得到了一个很好的答案,下面是我想到的另一个解释

假设我有这个:

async function func(x) {
    ...
    return y;
}

async function func2(x) {
    ...
    return await func(x);
}

async function func3(x) {
    let y = await func2(x);
    ...
}
我之所以可以安全地删除
func2
上返回语句中的
wait
,是因为在
func3
中调用
func2
时,我已经有了一个
wait

所以本质上,在上面的
func3
中,我有一些类似于
await-await-func(x)


当然,这并没有什么害处,所以最好保持
等待
,以确保所需的操作。

等待
只允许在
异步
函数中使用时,将承诺视为值

另一方面,
async
的工作原理正好相反,它将函数标记为返回承诺,即使它碰巧返回了一个真实的同步值(这对于异步函数来说听起来很奇怪……但当您有一个函数返回一个值或基于条件的承诺时,这种情况经常发生)

因此:

  • 我的结论是,仅在返回声明中直接删除等待是“合法的”

async
函数的最后一个
return
语句中,您只是返回一个承诺,或者直接返回一个承诺、一个实值,或者使用
wait
关键字返回一个承诺作为值


因此,在return语句中使用
await
是非常多余的:您使用
await
将承诺转换为一个值—在异步执行的上下文中—但是函数的
async
标记将该值视为一个承诺

因此,在最后一个返回语句中删除
wait
总是安全的

PS:实际上,wait期望任何thenable,即具有
then
属性的对象:它不需要完全符合规范的承诺就可以工作,好吗

PS2:当然,在调用同步函数时,您可以始终删除
wait
关键字:它根本不需要。

一个始终返回一个

因此,请记住,这些异步函数的编写都是相同的:

// tedious, sometimes necessary
async function foo() {
    return new Promise((resolve) => resolve(1)))
}

// shorter
async function foo() {
    return Promise.resolve(1)
}

// very concise but calling `foo` still returns a promise
async function foo() {
    return 1 // yes this is still a promise
}
您可以通过
foo()调用它们。然后(console.log)
打印
1
。或者您可以通过
await foo()
从另一个异步函数调用它们,但并不总是需要立即等待承诺

正如其他答案所指出的,
await
在成功时将承诺解析为实际返回值语句(或在失败时抛出异常),而如果没有
await
,则只会返回一个挂起的承诺实例,该实例将来可能成功或失败

省略的另一个用例(即:小心它的用法)
wait
是在编写异步代码时,您可能最希望并行化任务<代码>等待会在这里妨碍您

在异步函数的范围内比较以下两个示例:

async function func(x) {
    ...
    return y;
}
async function func() {
    const foo = await tediousLongProcess("foo") // wait until promise is resolved
    const bar = await tediousLongProcess("bar") // wait until promise is resolved

    return Promise.resolve([foo, bar]) // Now the Promise of `func` is marked as a success. Keep in mind that `Promise.resolve` is not necessary, `return [foo, bar]` suffices. And also keep in mind that an async function *always* returns a Promise.
}
与:

第一个将比最后一个花费更长的时间,因为顾名思义,每个
等待将停止执行,直到您解决第一个承诺,然后是下一个承诺

在第二个示例中,承诺将同时挂起并解决任何顺序,一旦所有承诺都解决,结果将被排序

(Bluebird promise库还提供了一个很好的函数,您可以将并发定义为
promise。所有的
都可能会破坏您的系统。)


我只在需要处理实际值时使用
wait
。如果我只想要一个承诺,就不需要等待它的值,在某些情况下,它实际上可能会损害代码的性能。

例如,当您拥有大数据并且不想丢失时
async function func() {
     promises = [tediousLongProcess("foo"), tediousLongProcess("bar")]
     return Promise.all(promises) // returns a promise on success you have its values in order
}