Files
endorphin-tabularium-docs/content/docs/pretext/02-chapter.md
T
codex-bot 2b3b3a1ae4
Verify and deploy Tabularium / verify-and-deploy (push) Successful in 5m47s
Expand document collections with Pretext tutorial and simplify library navigation
2026-10-28 13:42:51 +08:00

62 lines
2.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第二章:先看懂 prepare 与 layout 的分工
### 2.1 同一份输入,有不同的变化频率
聊天消息的文字和字体可能很久不变,但容器宽度会在拖动窗口时连续变化。把所有工作绑在一个函数里,每次 resize 都会重复做许多相同的事情。
Pretext 将它拆成两步:
```js
import { prepare, layout } from '@chenglou/pretext'
const prepared = prepare('Hello 世界,今天一起读源码。', '16px Arial')
const narrow = layout(prepared, 200, 24)
const wide = layout(prepared, 400, 24)
```
这里 `200`、`400` 是内容宽度,`24` 是调用者指定的每行高度,单位都是 CSS 像素。
| 阶段 | 输入 | 主要工作 | 什么时候重做 |
| --- | --- | --- | --- |
| `prepare()` | 文字、字体、选项及语言环境 | 分析断行机会、测量、记录修正数据 | 相关输入变化 |
| `layout()` | prepared、宽度、行高 | 根据已知宽度决定换行并计数 | 容器宽度或行高变化 |
prepared 可以理解为“已经整理好的排版材料”。它与容器宽度无关,但并不包含任意宽度下现成的布局答案。
### 2.2 沿源码走一遍
打开 [`src/layout.ts`](https://github.com/chenglou/pretext/blob/0d102a5cd933611e86a7e60bda7b4baa5995c6b0/src/layout.ts),定位 `prepareInternal()`:
```text
读取引擎规则与语言
→ analyzeText(...)
→ measureAnalysis(...)
→ prepared handle
```
再定位 `layout()`,其核心逻辑是:
```js
const lineCount = countPreparedLines(internal, normalizedWidth)
return { lineCount, height: lineCount * lineHeight }
```
这是省略类型与内部转换的源码摘义。它没有逐行调用 Canvas,也没有先创建 DOM 再读取高度。
### 2.3 一段文字被布局多次,省下多少工作
用 `P` 表示准备成本,用 `L` 表示一次布局成本,一共布局 `k` 次:
```text
复用 prepared:P + k × L
每次重新 prepare:k × (P + L)
```
两种写法相差 `(k - 1) × P`。这解释了为什么使用方式会直接决定收益:在 resize 回调中重新 prepare,会让原本可以省掉的分析工作再次发生。
另外,重复 prepare 可能命中测量缓存,但仍要分析文本、组装新的 handle。它依然比直接复用已有 handle 做得更多。
本章检查:`layout()` 是 O(1) 吗?不是。它通常还要扫描分段。快来自减少每一步要做的工作,而不是完全不看文本。