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
}