perf+feat: 掃描/佈局提速(中間/S4+S1)+增量恢復(Tier3 C1/C3/C2)
承 Tier1(S2+S3,已於 main 168e9e7)。本批為效能第二層+第三層,全程獨立複驗(差分/往返/ 增量≡全量/進程隔離測速/真瀏覽器)+4 份真人撰寫真實文檔驗收,行為保真、提速真實。 掃描層(無狀態、保行為): - 中間發現+S4:insidePill/isAvoided 之「逐文本節點沿祖先鏈」以 ancestorOrSelfPill/…Avoided 迭代回填記憶化(每元素恰算一次、兄弟共用祖先鏈快取),O(文本×depth)→O(元素)。實測掃描層 el.matches() 累計約降五成;深嵌套 render 進程隔離墻鐘 pre-Tier1 707ms→254ms(2.8×)。 佈局層(僅瀏覽器、正確性敏感): - S1 gapTrim 對齊門:尾隨 margin 僅在右緣 flush 之對齊可見,唯 left/start(ltr) 之 ragged 右緣 可整批跳過,省其 O(gaps) 次同步重排。實測非兩端對齊內容 gapTrim 數千 ms→數十 ms;justify/ center/right/RTL 保留完整逐一定案、行為不變(真瀏覽器差分:justify trim 集指紋逐位相同)。 增量恢復(第三層,向下兼容 API): - C1 持久化 Finder:跨 render 復用元素鍵快取(category/level/feature/祖先游走)。正確性靠 失效:新增 finder.invalidate(el) 清整棵子樹快取(祖先屬性變則後代快取變脏),revert 自動失效 其子樹(安全預設)。 - C3 rerender(root)=revert+render;局部恢復(實測編輯 400 段中一段 766×、matches 1441×)。 - C2 observe/disconnect:MutationObserver 自動增量——內容/分類屬性變化重處理最近塊、新增之塊 直接 render;render/revert 期間暫停觀察,自身注入絕不自觸發。 - append 修復(IV-3 差分複驗發現、單測漏掉):向葉塊(帶 jz-orphan)追加子塊使其轉非葉,須撤 容器陳舊 orphan——追加塊時若塊級父有 jz-orphan 直接子則改重處理該父。 測試 130→140(+S2 非葉塊、C1/C3、C2 觀察/失效/append、不自觸發)。基準設施:bench-incremental (增量恢復)、bench-layout(版面層,headless Chrome)。dist 重建。
This commit is contained in:
+29
-1
@@ -249,12 +249,40 @@ export const lineEdgePass: StandalonePass = {
|
||||
|
||||
const TRIM = "jz-hws-trim";
|
||||
|
||||
// 尾隨 margin-right 是否**可見**、需去行末隙,取決於容器對齊:
|
||||
// · justify/justify-all → 右緣 flush,行末 margin 內縮右緣 0.25em(需去);
|
||||
// · right/end(ltr) → 內容離右緣 0.25em(需去);· center → 行內容含 margin 一併置中、
|
||||
// 偏移 0.125em(需去);
|
||||
// · **left/start(ltr) → 右緣 ragged,行末 margin 落於不可見側**(可跳過)。
|
||||
// 唯 left/start(ltr) 可安全整批跳過,省其每個 O(gaps) 次同步重排(S1:常見之非兩端對齊左
|
||||
// 起內容零成本;其餘對齊之逐一定案為 margin 機制固有代價、保留)。RTL 一律保留(保守)。
|
||||
// text-align/direction 皆繼承,故同一 parentElement 下之間隙共用同值,per-parent memo。
|
||||
function skippableAlign(g: Element, cache: Map<Element, boolean>): boolean
|
||||
{
|
||||
const key = g.parentElement;
|
||||
if (!key) { return false; }
|
||||
const cached = cache.get(key);
|
||||
if (cached !== undefined) { return cached; }
|
||||
let result = false;
|
||||
const view = g.ownerDocument ? g.ownerDocument.defaultView : null;
|
||||
if (view)
|
||||
{
|
||||
const cs = view.getComputedStyle(g);
|
||||
const ltr = cs.direction !== "rtl";
|
||||
result = cs.textAlign === "left" || (cs.textAlign === "start" && ltr);
|
||||
}
|
||||
cache.set(key, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
function trimGaps(root: Element, finder: Finder, wrapSet: Set<string>): void
|
||||
{
|
||||
const alignCache = new Map<Element, boolean>();
|
||||
const gaps = Array.from(root.querySelectorAll("jz-hws")).filter(
|
||||
(g) => finder.inScope(g) && !finder.isAvoided(g)
|
||||
&& finder.levelAllows(g, "paragraph")
|
||||
&& finder.featureEnabledFor(g, "spacing"),
|
||||
&& finder.featureEnabledFor(g, "spacing")
|
||||
&& !skippableAlign(g, alignCache),
|
||||
);
|
||||
if (!gaps.length) { return; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user