Skip to content

Rolldown 中的顶层等待 (TLA)

¥Top Level Await(TLA) in Rolldown

背景知识:

¥Background knowledge:

下滚如何处理 TLA

¥How rolldown handles TLA

目前,rolldown 中支持 TLA 的原则是:我们将使其在打包后运行,但不保留原始代码的 100% 语义。

¥At this point, the principle of supporting TLA in rolldown is: we will make it work after bundling without preserving 100% semantic as the original code.

当前规则:

¥Current rules are:

  • 如果你的输入包含 TLA,则只能以 esm 格式打包和发送。

    ¥If your input contains TLA, it could only be bundled and emitted with esm format.

  • require TLA 模块被禁用。

    ¥require TLA module is forbidden.

并发到顺序

¥Concurrent to sequential

TLA 在 rolldown 中的一个缺点是它会将原始代码的行为从并发更改为顺序。它仍然确保了相对顺序,但确实会减慢执行速度,并且如果原始代码依赖于并发,可能会中断执行。

¥One downside of TLA in rolldown is that it will change the original code's behavior from concurrent to sequential. It still ensures the relative order, but indeed slows down the execution and may break the execution if the original code relies on concurrency.

实际示例如下:

¥A real-world example would looks like

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';

打包后,它将

¥After bundling, it will be

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 foo1foo2 是顺序解析的,但在原始代码中,它们是并发解析的。

¥You can see that, in bundled code, promise foo1 and foo2 are resolved sequentially, but in the original code, they are resolved concurrently.

有一个非常详细的 TLA 规范代码库,它解释了 TLA 工作原理的思维模型。

¥There's a very good example of TLA spec repo, which explains the mental model of how the TLA works

js
import { a } from './a.mjs';
import { b } from './b.mjs';
import { c } from './c.mjs';

console.log(a, b, c);

脱糖后可视为以下代码:

¥could be considered as the following code after desugaring:

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 中,打包后的内容如下所示:

¥However, in rolldown, it will looks like this after bundling:

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);