await-vs-return-vs-return-await

await vs return vs return await

在写async函数时,awaitreturnreturn await是不同的,选择正确的写法很重要。

从下面这个async函数开始吧:

1
2
3
4
5
6
7
8
9
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!');
}

这个函数1秒后返回一个Promise,返回yay和抛出异常的概率都是50%。下面我们用不同的方式调用它:

Just calling

1
2
3
4
5
6
7
8
9
async function foo() {
try {
// waitAndMaybeReject 将返回一个 promise;
waitAndMaybeReject();
}
catch (e) {
return 'caught';
}
}

如果你调用foo,返回的promise对象总是立即返回undefined,不会等待。

因为我们没用await或者return执行waitAndMaybeReject函数,对于waitAndMaybeReject我们不能做什么。这种写法一般是错的。

waitAndMaybeReject会立即返回一个promise,foo函数会立即结束。我们不会看到waitAndMaybeReject函数内部延迟执行的1s。waitAndMaybeReject函数内部抛出的任何异常和结果我们也无法捕获或者接受。

Awaiting

1
2
3
4
5
6
7
8
async function foo() {
try {
await waitAndMaybeReject();
}
catch (e) {
return 'caught';
}
}

如果你调用foo,返回的promise将在1秒后返回一个undefined或者caught

因为我们等待waitAndMaybeReject()的执行结果,它抛出的异常将会被catch语句捕获,如果它正常执行这个函数什么将不会返回任何值undefined

这里相当于调用了waitAndMaybeReject函数,如果waitAndMaybeReject抛出异常我们将忽略掉异常重新返回一个caught字符串,如果waitAndMaybeReject没有抛出异常,foo函数将无返回值undefined

Returning

1
2
3
4
5
6
7
8
async function foo() {
try {
return waitAndMaybeReject();
}
catch (e) {
return 'caught';
}
}

如果你调用foo,这个返回的promise对象将等待1秒后返回yay或者抛出一个Boo!异常。

这里我们foo的返回值其实就是waitAndMaybeReject的返回值,我们的catch语句将永远不会执行。

这个foo函数的封装毫无意义,相当于直接调用waitAndMaybeReject

Return-awaiting

1
2
3
4
5
6
7
8
async function foo() {
try {
return await waitAndMaybeReject();
}
catch (e) {
return 'caught';
}
}

我们调用foo后,返回的promise将等待1秒后返回一个yay或者caught

当我们等待waitAndMaybeReject()的结果时,它如果抛出异常将被我们的catch语句捕获,我们会返回一个catch字符串,如果这个函数正常执行,我们将返回它的返回值yay

我们将上面函数拆分成两步就是下面的形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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';
}
}

注意:如果没有try/catch包裹的return await函数是冗余的,可以使用ESLint去检测。但是在try/catch里面是允许的。

如果没有try/catch包裹时waitAndMaybeReject抛异常,将会从foo里面抛出去,如果正确返回将会从foo的结果中获取。这相当于return waitAndMaybeReject(),我们直接使用waitAndMaybeReject()返回的promise比foo返回的promise更简单清晰。

参考

本站采用「署名 4.0 国际」进行许可。