docs: changelog 2026-07-11 效能第一層——掃描提速(category 記憶化 + orphan 葉塊預計算)

新增 changelog 條目+md-twin 同步。下游效能訴求一之第一層:S3 category 以 WeakMap 記憶化砍除跨
pass 重複 el.matches()(實測約降三成)、S2 orphan 以上攀預計算「非葉塊」取代逐塊 querySelector 掃
子樹之 O(Σ塊子樹)。皆無狀態、保行為、無公開 API 變更;測試 129→130 全綠。並記亲驗數據與 insidePill
之下一機會。changelog HTML 經 build.sh 重建。
This commit is contained in:
2026-07-11 19:58:41 +08:00
parent cda0903089
commit fdad106980
2 changed files with 326 additions and 110 deletions
+29
View File
@@ -25,6 +25,19 @@
<!-- BODY -->
<p class="lede">聚珍(Juzhen)/cjk-autospace 變更紀錄。<a href="./index.html">← 回文檔</a></p>
<h2>效能第一層:掃描提速(category 記憶化 + orphan 葉塊預計算) <span class="badge accent">2026-07-11</span></h2>
<p>下游效能訴求(掃描疑 O(n²))之第一層——無狀態、保行為、無公開 API 變更之確定收益。單元測試 129→130 全綠、輸出不變。</p>
<h3>優化</h3>
<ul>
<li><strong>S3 category 記憶化</strong><code>finder.category</code><code>WeakMap&lt;Element, InlineCategory&gt;</code> 記憶化,砍除 <code>collectRuns</code><code>jiyaAdjacency</code><code>jinze</code><code>split</code> 跨 pass 對同一元素之重複 <code>el.matches()</code>pillisolateavoid 選擇器)。實測 pillisolate 密集頁面 <code>el.matches()</code> 8204→5842(約降三成,命中率 55%)。安全:單次 render 內一元素之分類恆定、且 Finder 隨 <code>makeCtx</code> 每次 render 重建 → 快取僅存活單次 render、無跨 render 失效(持久化屬另議)。</li>
<li><strong>S2 orphan 葉塊預計算</strong>:以一趟上攀預計算「非葉塊」Set 取代逐塊 <code>block.querySelector(sel)</code> 掃整棵子樹之 O(Σ塊子樹)(深塊嵌套下 O(n²));某塊為另一塊之最近塊祖先 ⟺ 含塊級後代,與原 querySelector 同口徑、行為等價。</li>
</ul>
<h3>亲驗與待議</h3>
<ul>
<li>亲驗:暫禁 category 快取則 <code>computeCategory</code> 由 1041 增至 2322、<code>el.matches()</code> 由 5842 增至 8204——證快取真減負而非空操作(初次插桩誤打 <code>HTMLBodyElement.prototype</code> 而漏計,改補 <code>Element.prototype.matches</code> 後為準)。</li>
<li>新發現(下一機會):剩餘 <code>el.matches()</code> 之最大來源為 <code>insidePill</code> 之「逐文本節點沿祖先鏈 <code>pillMatches</code>」(<code>eachTextNode</code> 每文本節點一趟、未記憶化)。</li>
</ul>
<h2>splitTreeAfter 攀升對稱守衛(opaque 中間祖先不再被克隆肢解) <span class="badge accent">2026-07-11</span></h2>
<p>下游 <code>.selection-bar-message</code> 病例:垂懸字(orphan)之段末實義字落於 opaque <code>&lt;button&gt;</code>(巢於可切 <code>&lt;span&gt;</code>)時,<code>splitElementAt</code> 僅驗頂層 span 可切;<code>splitTreeAfter</code> 逐層克隆「文本節點→top」祖先鏈時,中間 opaque button 從未複查即被克隆肢解(複製出 <code>splitoff</code> button、破壞互動元素)。<code>firstText</code><code>lastText</code> 守下潛(遇非可切回 <code>null</code>),攀升卻無對稱守衛——此即真正病根,下游 per-instance 迴避僅治標。</p>
<h3>修復</h3>
@@ -243,6 +256,22 @@
<script type="text/markdown" id="md-source">
# 變更紀錄Changelog 聚珍Juzhencjk-autospace
## 效能第一層掃描提速category 記憶化 orphan 葉塊預計算2026-07-11
下游效能訴求掃描疑 O()之第一層無狀態保行為無公開 API 變更測試 129130 全綠輸出不變
### 優化
- S3 category 記憶化finder.category WeakMap<Element,InlineCategory> 記憶化砍除各遍歷原語跨 pass
對同一元素之重複 el.matches()實測 pill/isolate 密集頁 el.matches() 82045842約降三成命中率 55%
安全單次 render 內分類恆定Finder 每次 render 重建 快取僅存活單次 render無跨 render 失效
- S2 orphan 葉塊預計算以一趟上攀預計算非葉塊Set 取代逐塊 block.querySelector(sel) 掃子樹之
O(Σ塊子樹)深塊嵌套 O()某塊為另一塊之最近塊祖先 含塊級後代與原 querySelector 同口徑等價
### 亲驗與待議
- 亲驗暫禁 category 快取則 computeCategory 10412322el.matches() 58428204初次插桩誤打
HTMLBodyElement.prototype 漏計改補 Element.prototype.matches 後為準
- 新發現下一機會剩餘 el.matches() 最大來源為 insidePill 之逐文本節點沿祖先鏈 pillMatches未記憶化
## splitTreeAfter 攀升對稱守衛opaque 中間祖先不再被克隆肢解2026-07-11
下游 .selection-bar-message 病例垂懸字段末實義字落於 opaque `<button>`巢於可切 `<span>`splitElementAt 僅驗頂層 spansplitTreeAfter 逐層克隆文本節點top祖先鏈時中間 opaque button 從未複查即被克隆肢解複製出 splitoff buttonfirstTextlastText 守下潛攀升卻無對稱守衛真正病根下游 per-instance 迴避僅治標