区分await、return以及return await
当我们写 async 函数的时候,需要注意 await、return 以及 return await 的区别,并作出正确的选择。
我们先来看一个 async 函数:
async function waitAndMaybeReject() {
// Wait one second
await new Promise((r) => setTimeout(r, 1000))
// Toss a coin
const isHeads = Boolean(Math.round(Math.random()))
if (isHeads) return 'yay'
throw Error('Boo!')
}
调用这个函数会返回一个 promise,等待一秒后,50%的可能性 fulfill,返回值为"yay",另外 50%的可能性会 reject 一个错误。下面我们用几种不同的姿势来使用这个 async 函数。
Just Calling
async function foo() {
try {
waitAndMaybeReject()
} catch (e) {
return 'caught'
}
}
如果调用上面的 foo 函数,会立即返回一个 promise,并且 fulfill 的值为 undefined。
因为我们没有 await 或者 returnwaitAndMaybeReject()
调用的结果。像上面这样的代码,通常而言是写错了。
Awaiting
async function foo() {
try {
await waitAndMaybeReject()
} catch (e) {
return 'caught'
}
}
如果调用上面的 foo 函数,返回的 promise 会等待一秒钟,然后 fulfill,返回值要么是 undefined,要么是“caught”。
因为我们 await 了waitAndMaybeReject()
调用的结果。waitAndMaybeReject()
调用返回一个 promise,如果 reject,会被当做一个异常抛出,因而 catch 代码块会被执行。但是如果 fulfill,foo 函数并没有处理该情况的返回值。
Returning
async function foo() {
try {
return waitAndMaybeReject()
} catch (e) {
return 'caught'
}
}
如果调用上面的 foo 函数,返回的 promise 会等待一秒钟,然后要么 fulfill,返回值为“yay”,要么 reject 一个Error('Boo!')
错误。
因为返回了waitAndMaybeReject()
,所以 foo 函数调用返回的 promise 即为waitAndMaybeReject()
返回的 promise。没有异常, 因而 catch 代码块并不会执行。
Return-awaiting
如果 你的预期是上面的 catch 代码块有可能 执行,需要使用 return await:
async function foo() {
try {
return await waitAndMaybeReject()
} catch (e) {
return 'caught'
}
}
如果调用上面的 foo 函数,返回的 promise 会等待一秒钟,然后 fulfill,返回值为要么是“yay”,要么是“caught”。
因为我们 await 了waitAndMaybeReject()
函数调用的结果,它返回的 promise 如果 reject 会抛出异常,此时 catch 代码块就会执行。但如果waitAndMaybeReject()
返回的 promise 状态是 fulfill,则会返回 fulfill 的结果。
如果上面的代码看起来有点困惑,把它拆分成两步可能更容易理解:
async function foo() {
try {
// Wait for the result of waitAndMaybeReject() to settle,
// and assign the fulfilled value to fulfilledValue:
const fulfilledValue = await waitAndMaybeReject()
// If the result of waitAndMaybeReject() rejects, our code
// throws, and we jump to the catch block.
// Otherwise, this block continues to run:
return fulfilledValue
} catch (e) {
return 'caught'
}
}