sfl*_*che 10 javascript async-await
我看到有一个eslint规则,no-return-await禁止return await.
在规则的描述中,它表示return await添加"extra time before the overarching Promise resolves or rejects".
但是,当我查看MDN async函数文档时,"简单示例"显示了一个示例,其中return await不包含任何可能导致性能问题的描述.
是return await一个实际的性能问题,因为eslint文档建议?
如果是这样,怎么样?
Ber*_*rgi 24
不,没有任何性能问题.这只是一个不必要的额外操作.执行可能需要更长的时间,但应该难以察觉.它类似于整数return x+0而不是return x整数x.或者说,完全等同于毫无意义.then(x => x).
它并没有造成实际的伤害,但我认为这是一种不好的风格,并且表明作者没有完全理解承诺和async/ await.
但是,有一种情况会产生重大影响:
try {
…
return await …;
} …
Run Code Online (Sandbox Code Playgroud)
await确实抛弃拒绝,并且在任何情况下等待承诺解决catch或finally执行处理程序.平原return会忽略这一点.
Sho*_*use 24
我添加答案是因为评论太长。async我最初对如何工作和工作有一个非常长、详细的解释await。但它是如此复杂,实际数据可能更容易理解。所以这是呃,简化的解释。注意:这在 Chrome v97、FireFox v95 和 Node v16 上运行,结果相同。
关于什么更快的答案:这取决于您返回的内容以及您如何调用它。工作原理与它运行PromiseResolveawait不同(类似于但它是内部的)。基本上,如果你运行一个 Promise(一个真正的 Promise,而不是一个 polyfill),就不要尝试包装它。它按原样执行承诺。这会跳过一个刻度。这是 2018 年以来的“较新”更改。总之,评估始终返回 Promise 的结果,而不是 Promise,同时尽可能避免包装 Promise。这意味着总是至少需要一个刻度。asyncPromise.resolveawaitawaitawaitawait
但这实际上await并async没有使用这个旁路。现在async使用良好的PromiseCapability Record。我们关心这如何解决承诺。关键点是,如果决议是“不是Object”或.then不是,它将立即开始履行Callable。如果两者都不成立,(您返回 a Promise),它将执行 aHostMakeJobCallback并附加到thenPromise 中,这基本上意味着我们要添加一个勾号。澄清一下,如果你在函数中返回 Promise async,它会添加一个额外的勾号,但如果你返回 Non-Promise,则不会。
因此,在所有前言(这是简化版本)中,以下是您的图表,显示了await foo()调用返回之前有多少个刻度:
| 无承诺 | 承诺 | |
|---|---|---|
| () => 结果 | 1 | 1 |
| 异步()=>结果 | 1 | 3 |
| async () => 等待结果 | 2 | 2 |
这是用 测试的await foo()。您也可以使用 进行测试foo().then(...),但刻度是相同的。(如果你不使用 an await,那么同步函数确实会是 0。虽然foo().then会崩溃,所以我们需要一些真实的东西来测试。)这意味着我们的楼层是 1。
如果您理解我上面的解释(希望如此),那么这是有道理的。同步函数是有意义的,因为我们在函数中的任何时刻都不会调用暂停执行:await foo()将需要 1 个时钟周期。
async喜欢“无承诺”并期待它们。如果找到,它会立即返回。但如果它找到一个 Promise,它就会附加到该 Promise 的then. 这意味着它将执行 Promise (+1),然后等待then完成(另一个 +1)。这就是为什么它是 3 个刻度。
await将把 a 转换为完美的Promisea 。如果您在 a 上调用await ,它将执行它而不添加任何额外的刻度(+1)。但是,会将 a 转换为 a然后运行它。这意味着无论你反对什么,总是需要打勾。Non-PromiseasyncPromiseawaitNon-PromisePromiseawait
因此,总而言之,如果您想要最快的执行速度,您需要确保您的async函数始终包含至少一个await. 如果没有,那么只需使其同步即可。您始终可以调用await任何同步函数。现在,如果您想真正调整性能,并且要使用async,则必须确保始终返回 Non-Promise,而不是Promise。如果您要返回 a Promise,请先使用 进行转换await。也就是说,你可以像这样混合搭配:
async function getData(id) {
const cache = myCacheMap.get(id);
if (cache) return cache; // NonPromise returns immediately (1 tick)
// return fetch(id); // Bad: Promise returned in async (3 ticks)
return await fetch(id); // Good: Promise to NonPromise via await (2 ticks)
}
Run Code Online (Sandbox Code Playgroud)
考虑到这一点,我有一堆代码需要重写:)
参考:
https://v8.dev/blog/fast-async
测试:
async function test(name, fn) {
let tick = 0;
const tock = () => tick++;
Promise.resolve().then(tock).then(tock).then(tock);
const p = await fn();
console.assert(p === 42);
console.log(name, tick);
}
await Promise.all([
test('nonpromise-sync', () => 42),
test('nonpromise-async', async () => 42),
test('nonpromise-async-await', async () => await 42),
test('promise-sync', () => Promise.resolve(42)),
test('promise-async', async () => Promise.resolve(42)),
test('promise-async-await', async () => await Promise.resolve(42)),
]);
setTimeout(() => {}, 100);
Run Code Online (Sandbox Code Playgroud)