Rolldown 中的顶层 await(TLA)
背景知识:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top_level_await
- https://github.com/tc39/proposal-top-level-await
Rolldown 如何处理 TLA
现阶段,Rolldown 支持 TLA 的原则是:确保代码在打包后能够运行,但不保证百分之百保留原始代码的语义。
目前的规则如下:
- 如果输入包含 TLA,只能以
esm格式打包和输出。 - 禁止通过
require加载包含 TLA 的模块。
从并发变为顺序执行
Rolldown 中 TLA 的一个缺点是,它会将原始代码的并发行为改为顺序执行。虽然仍能保证相对顺序,但确实会降低执行速度;如果原始代码依赖并发行为,甚至可能导致程序无法正常运行。
下面是一个实际示例:
js
// main.js
import { bar } from './sync.js';
import { foo1 } from './tla1.js';
import { foo2 } from './tla2.js';
console.log(foo1, foo2, bar);
// tla1.js
export const foo1 = await Promise.resolve('foo1');
// tla2.js
export const foo2 = await Promise.resolve('foo2');
// sync.js
export const bar = 'bar';打包后会得到:
js
// tla1.js
const foo1 = await Promise.resolve('foo1');
// tla2.js
const foo2 = await Promise.resolve('foo2');
// sync.js
const bar = 'bar';
// main.js
console.log(foo1, foo2, bar);可以看到,在打包后的代码中,Promise foo1 和 foo2 会依次完成;而在原始代码中,它们是并发执行的。
TLA 规范仓库中有一个非常 清晰的示例,用于解释 TLA 的工作心智模型:
js
import { a } from './a.mjs';
import { b } from './b.mjs';
import { c } from './c.mjs';
console.log(a, b, c);可以把它理解为经过语法脱糖后的以下代码:
js
import { a, promise as aPromise } from './a.mjs';
import { b, promise as bPromise } from './b.mjs';
import { c, promise as cPromise } from './c.mjs';
export const promise = Promise.all([aPromise, bPromise, cPromise]).then(() => {
console.log(a, b, c);
});但在 Rolldown 中,打包后的效果类似于:
js
import { a, promise as aPromise } from './a.mjs';
import { b, promise as bPromise } from './b.mjs';
import { c, promise as cPromise } from './c.mjs';
await aPromise;
await bPromise;
await cPromise;
console.log(a, b, c);