Chipmunk & Panda

-- 鼠熊部落格

All work and no play makes Jack a dull boy.

ESLint no-return-await 规则

ESLint 原有 no-return-await 规则,旨在避免如下情景:

1
2
3
4
5
6
7
8
async function foo() {
return await bar()
}

async function baz() {
const barRes = await bar()
return barRes
}

在以前,无论等待的是什么,await 都会将之后的返回值包装为 Promise 对象(即使返回值本来就是个 Promise),故对外部而言,上述操作所实现的效果在未报错情况下等价于:

1
2
3
async function foo() {
return Promise.resolve(bar())
}

如此导致了一个不必要的微任务,从而影响性能。

Faster async functions and promises 修复了这个问题,仅在 await 的内容不是 Promise 时,才会使用 Promise.resolve 将其包裹起来,从而解决了原本的性能问题。

在改动之后,对于 Promise 对象,对其 await 再返回的性能不再会比直接返回差,甚至反直觉的是, await 再返回的性能甚至可能更好,这使得 no-return-await 从一个性能相关的规则退化成了一个代码风格相关的规则(具体的运行测试可以参见 Rule Change: return await is both faster and allows better error handling #17345):

1
2
3
4
5
6
7
/* https://github.com/tc39/proposal-faster-promise-adoption */

// Directly returning a promise settles `direct` after 2 ticks.
const direct = (async () => Promise.resolve(1))()

// Returning an awaited promise's value settles `awaited` after 1 ticks.
const awaited = (async () => await Promise.resolve(1))()

导致 no-return-await 被废弃的另一个原因在于 return await 可以提供更多的调用栈信息,尤其是当 return 位于 try catch 语句中时,使用 await 可以将错误栈保留在 async 函数中,而不会泄露到外部。

综上所述,no-return-await 已经不再推荐被使用,取而代之的是@typescript-eslint/return-await