await-vs-return-vs-return-await
await vs return vs return await
在写async
函数时,await
、return
和return await
是不同的,选择正确的写法很重要。
从下面这个async
函数开始吧:
1 | async function waitAndMaybeReject() { |
这个函数1秒后返回一个Promise,返回yay
和抛出异常的概率都是50%。下面我们用不同的方式调用它:
Just calling
1 | async function foo() { |
如果你调用foo
,返回的promise对象总是立即返回undefined
,不会等待。
因为我们没用await
或者return
执行waitAndMaybeReject
函数,对于waitAndMaybeReject
我们不能做什么。这种写法一般是错的。
waitAndMaybeReject
会立即返回一个promise,foo函数会立即结束。我们不会看到waitAndMaybeReject
函数内部延迟执行的1s。waitAndMaybeReject
函数内部抛出的任何异常和结果我们也无法捕获或者接受。
Awaiting
1 | async function foo() { |
如果你调用foo
,返回的promise将在1秒后返回一个undefined
或者caught
。
因为我们等待waitAndMaybeReject()
的执行结果,它抛出的异常将会被catch
语句捕获,如果它正常执行这个函数什么将不会返回任何值undefined
。
这里相当于调用了
waitAndMaybeReject
函数,如果waitAndMaybeReject
抛出异常我们将忽略掉异常重新返回一个caught
字符串,如果waitAndMaybeReject
没有抛出异常,foo
函数将无返回值undefined
。
Returning
1 | async function foo() { |
如果你调用foo
,这个返回的promise对象将等待1秒后返回yay
或者抛出一个Boo!
异常。
这里我们foo
的返回值其实就是waitAndMaybeReject
的返回值,我们的catch
语句将永远不会执行。
这个
foo
函数的封装毫无意义,相当于直接调用waitAndMaybeReject
。
Return-awaiting
1 | async function foo() { |
我们调用foo
后,返回的promise将等待1秒后返回一个yay
或者caught
。
当我们等待waitAndMaybeReject()
的结果时,它如果抛出异常将被我们的catch
语句捕获,我们会返回一个catch
字符串,如果这个函数正常执行,我们将返回它的返回值yay
。
我们将上面函数拆分成两步就是下面的形式:1
2
3
4
5
6
7
8
9
10
11
12
13
14async 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更简单清晰。