Type
Suggestion
Description
从目录点击章节后有明显等待。两端从 view.goTo 起完全共用 vendored foliate-js,所以这是一个内核层问题,不是某一端的问题。
Paginator.#goTo(paginator.js:2895)有两条路:
快路径 (:2915-2963):目标 section 已在 #views 里,只换 primary,几十毫秒
慢路径 (:2965-2996):目录跳到非相邻章必然走这条
慢路径的 #display 一进来就 opacity = '0'(paginator.js:2682),到 :2737 才恢复 '1',中间全部串行 await:
步骤
位置
问题
zip 解压整章
view.js:32 等三处 useWebWorkers:false
跑在主线程
DOMParser 解析
epub.js:1081
第 1 次解析
9 组资源改写
epub.js:1119-1140
全部串行 await ,可并发
XMLSerializer
epub.js:1157
第 2 次(序列化)
iframe.srcdoc
paginator.js:516-519
浏览器第 3 次解析同一份内容
背景图等待
paginator.js:485-491
最长 3000ms 硬等待
columnize + 逐图 getComputedStyle
paginator.js:565-705
expand() 全章强制重排
paginator.js:713-745
一次跳章通常跑 2-3 次
同步预加载上一章
paginator.js:2717-2730
分页模式下短章还要等它
揭示之后还有 #fillVisibleArea(:2822)串行补最多 8 个 section ,每个都完整重跑上面这条流水线 —— 这对应「正文出来了但一两秒内点不动」。
另一个关键点:Loader 没有 LRU
epub.js:996 引用计数归零就立刻 URL.revokeObjectURL + 删缓存,#cache / #cacheXHTMLContent 全文没有任何容量上限或逐出策略。而慢路径的 keep 只保留 index ±2(paginator.js:2974-2978),跨章跳转必然销毁其余 view。结果是来回跳章第二次仍然全量重解析 ,连全书共享的 style.css / 字体也被 revoke 掉。
建议(按性价比排序)
给 Loader 加容量固定的 LRU :unref 到 0 时不立刻 revoke,改为入队(XHTML 6-10 条 + CSS/字体常驻池)。loadItem 已有命中路径(epub.js:1021),只需让缓存活得更久。收益最直接。
epub.js:1119-1140 的串行 await 改成 Promise.all 并发(需补 in-flight 去重)。
paginator.js:489 的背景图 setTimeout(res, 3000) 降到 150-300ms —— img.onload 里已有兜底路径(:473-477)。
paginator.js:2747 把 #fillVisibleArea 推迟到首帧之后(rAF + setTimeout 0),让正文先可交互;:3060 的 await this.#fillPromise 改成带 50ms 超时的 race。
expand() 结果按 layout 签名缓存;fonts.ready 与 ResizeObserver 两路 expand 合并去抖到同一帧。
桌面端 FoliateViewer.tsx:2088-2137 的整章 TreeWalker 挡在 opacity='1' 之前,直接计入白屏时长(详见 [Perf] 章内翻页固定多付 100ms,且一次翻页触发两次 relocate #749 )。
说明
全部来自代码路径静态分析,没有实测 profile。 各步骤真实耗时占比(解压 vs DOMParser vs expand vs 宿主回调)未知,建议在 #display 的 opacity 0→1 之间打几个 performance.mark 实测一次再定优先级。
特别提醒:useCompressionStream 仍为 true,实际 inflate 走原生 DecompressionStream,所以「zip 解压在主线程」这条的收益可能远小于直觉,不建议当第一优先级。
Related
Type
Suggestion
Description
从目录点击章节后有明显等待。两端从
view.goTo起完全共用 vendored foliate-js,所以这是一个内核层问题,不是某一端的问题。Paginator.#goTo(paginator.js:2895)有两条路:#views里,只换 primary,几十毫秒慢路径的
#display一进来就opacity = '0'(paginator.js:2682),到 :2737 才恢复'1',中间全部串行 await:useWebWorkers:falseawait,可并发揭示之后还有
#fillVisibleArea(:2822)串行补最多 8 个 section,每个都完整重跑上面这条流水线 —— 这对应「正文出来了但一两秒内点不动」。另一个关键点:Loader 没有 LRU
epub.js:996引用计数归零就立刻URL.revokeObjectURL+ 删缓存,#cache/#cacheXHTMLContent全文没有任何容量上限或逐出策略。而慢路径的keep只保留index ±2(paginator.js:2974-2978),跨章跳转必然销毁其余 view。结果是来回跳章第二次仍然全量重解析,连全书共享的 style.css / 字体也被 revoke 掉。建议(按性价比排序)
loadItem已有命中路径(epub.js:1021),只需让缓存活得更久。收益最直接。epub.js:1119-1140的串行 await 改成Promise.all并发(需补 in-flight 去重)。paginator.js:489的背景图setTimeout(res, 3000)降到 150-300ms ——img.onload里已有兜底路径(:473-477)。paginator.js:2747把#fillVisibleArea推迟到首帧之后(rAF + setTimeout 0),让正文先可交互;:3060 的await this.#fillPromise改成带 50ms 超时的 race。expand()结果按 layout 签名缓存;fonts.ready与 ResizeObserver 两路 expand 合并去抖到同一帧。FoliateViewer.tsx:2088-2137的整章 TreeWalker 挡在opacity='1'之前,直接计入白屏时长(详见 [Perf] 章内翻页固定多付 100ms,且一次翻页触发两次 relocate #749)。说明
全部来自代码路径静态分析,没有实测 profile。 各步骤真实耗时占比(解压 vs DOMParser vs expand vs 宿主回调)未知,建议在
#display的 opacity 0→1 之间打几个performance.mark实测一次再定优先级。特别提醒:
useCompressionStream仍为 true,实际 inflate 走原生 DecompressionStream,所以「zip 解压在主线程」这条的收益可能远小于直觉,不建议当第一优先级。Related
paginator.js:3001的if (this.#locked) return静默丢弃