ReadViewSDK/Doc/SDK架构整改路线图.md
shen 7de661eb54 feat: 架构整改 — Context拆分、Runtime拆分、异步章节加载、UI测试覆盖
Phase 1: Context 拆分
- 新增 RDEPUBReaderState/RDEPUBReaderEnvironment/RDEPUBReaderServices
- RDEPUBReaderContext 改为过渡门面,代理到 State/Environment/Services

Phase 2: Runtime 拆分
- 新增 RDEPUBPresentationRuntime 处理分页状态管理
- 新增 RDEPUBChapterWarmupOrchestrator 处理章节预热与加载编排
- RDEPUBReaderRuntime 从 1277 行收缩,公共 API 转发到新 facade

Phase 0.5: 性能优化
- prepareOnDemandChapter 支持异步模式(allowSynchronousLoad: false)
- extendPartialBookPageMapIfNeeded 改为 DispatchGroup 并发加载
- RDEPUBChapterOffsetMap.cfiMap 加 NSLock 保护数据竞争
- CFI Map 构建延迟到后台队列(scheduleDeferredCFIMapBuildIfNeeded)
- RDEPUBTextPageRenderView 引入静态位图缓存
- RDEPUBTextContentView 新增 loadingSpinner 占位页

Phase 3: 状态机
- 新增 RDEPUBNavigationStateMachine(含 DEBUG 合法转换校验)
- 新增 RDEPUBPaginationState 记录分页来源

Review 修复
- makeSummary 重复方法合并
- ensureNavigationTargetAvailable 同步路径加注释标记

UI 测试
- 新增 AsyncChapterLoadingTests(20 个测试,覆盖全部架构整改场景)
- 跨章节翻页、延迟 CFI、状态机、内存警告、预加载、位置恢复等
2026-06-23 08:17:08 +08:00

22 KiB
Raw Blame History

ReadViewSDK 架构整改路线图

最后更新2026-06-22 适用范围:Sources/RDReaderView/ 下的 EPUB 阅读器 SDK 主体代码 目标性质:可执行整改方案,而不是纯讨论文档


1. 文档目标

本文将当前 SDK 的架构问题整理为一份可逐阶段推进的整改路线图,目标是解决以下五类核心问题:

  1. 共享状态与 UI 环境混杂,导致隐藏依赖过多。
  2. 运行时协调中心过大,新增需求持续回流到单一大类。
  3. 章节加载、分页、定位、选区等关键链路存在同步边界与模型重复。
  4. 阅读容器层、业务控制层、渲染能力层之间的职责边界还不够稳定。
  5. 用户感知最强的性能问题缺少独立的优先修复阶段。

本文不追求一次性重写,而强调:

  • 先收口依赖方向
  • 再拆核心状态与服务
  • 最后统一抽象与模块边界

2. 当前架构问题摘要

基于当前代码,主要问题集中在以下对象与层次:

2.1 RDEPUBReaderContext 过重

涉及文件:

  • Sources/RDReaderView/EPUBUI/ReaderController/RDEPUBReaderContext.swift

当前同时承担:

  • 共享状态容器
  • UI 环境查询入口
  • service locator
  • render/layout 参数推导
  • controller/runtime 反向跳转

这会让下层对象表面上只依赖 context,实际上隐式依赖整棵 UI 树与运行时生命周期。

2.2 RDEPUBReaderRuntime 过大

涉及文件:

  • Sources/RDReaderView/EPUBUI/ReaderController/RDEPUBReaderRuntime.swift

当前问题:

  • 持有大量 coordinator
  • 继续承接大量 facade API
  • 同时编排分页、章节窗口、选区、书签、高亮、设置预览、page map 替换等多领域逻辑

结果是 runtime 已经成为事实上的架构中心点。

2.3 存在危险同步边界

涉及文件:

  • Sources/RDReaderView/EPUBUI/ReaderController/ChapterRuntime/RDEPUBChapterLoader.swift
  • Sources/RDReaderView/EPUBUI/ReaderController/RDEPUBReaderContext.swift

当前风险:

  • 同步章节加载仍保留在系统内部
  • 后台线程获取分页尺寸时可能回主线程同步查询
  • 长链路上仍可能形成“主线程等后台,后台等主线程”的死锁型结构

2.4 分页状态模型重复

涉及对象:

  • bookPageMap
  • pendingFullPageMap
  • chapter window snapshot
  • readingSession.activePages/activeChapters

当前问题:

  • 多套近似模型并存
  • takeover/reconciliation 规则分散
  • 维护“当前阅读窗口”的逻辑被多个对象共同持有

2.5 RDReaderView 既是容器又是兼容层

涉及文件:

  • Sources/RDReaderView/ReaderView/RDReaderView.swift
  • Sources/RDReaderView/ReaderView/RDReaderViewProtocols.swift

当前问题:

  • 同时承载 page curl / scroll / dual-page / preload / tool chrome
  • 同时兼容 RDReaderDataSourceRDReaderPageProvider
  • 既做分页容器,又承担历史 API 适配职责

3. 整改原则

整改过程中遵循以下原则:

  1. 不做一次性全量重写,采用分阶段替换。
  2. 优先解决依赖方向错误,再解决类过大问题。
  3. 所有阶段都必须保持 Demo 可运行、SDK 公共 API 尽量兼容。
  4. 先抽象内部接口,再清理外部旧接口。
  5. 每个阶段结束时必须有可验证的稳定输出。

4. 总体阶段划分

建议分为 6 个阶段推进:

  1. Phase 0建立基线与护栏
  2. Phase 0.5:优先消除主线程同步加载与跨章节翻页卡顿
  3. Phase 1收缩 Context,切开环境与状态
  4. Phase 2拆分 Runtime 与章节加载编排
  5. Phase 3统一分页状态模型与导航状态机
  6. Phase 4收敛 ReaderView 抽象与模块边界

建议执行顺序不可颠倒。

原因:

  • 如果不先建立基线,后续性能与结构整改缺少可验证参照。
  • 如果不先把最强用户痛点独立处理,后续阶段虽然架构更干净,但用户体感改善会滞后。
  • Context 拆分是中期结构整改前置条件,但不是修复同步加载卡顿的前置条件。
  • 如果不先拆 Runtime,分页模型和容器抽象重构会继续回流到 runtime。
  • 如果不先统一分页状态模型,后续 UI/容器抽象无法稳定。

5. Phase 0建立基线与护栏

5.1 目标

在重构前建立可回归的技术基线,避免“结构越改越好,但行为逐渐漂移”。

5.2 主要工作

  1. 建立架构整改分支与阶段文档索引。
  2. 为以下关键链路补 smoke 验证清单:
    • 打开一本大书
    • 跨章节连续翻页
    • 恢复上次阅读位置
    • 搜索关键字并跳转
    • 长按选区并添加高亮
    • 打开目录远跳
  3. 补充日志观察点:
    • 章节首次构建耗时
    • bookPageMap 扩展/替换次数
    • CFI 延迟构建完成次数
    • 页面静态底图缓存命中率
  4. 把“禁止 UI 主路径同步章节加载”加成断言或日志告警。
  5. 补充用户感知最直接的观测指标:
    • 翻页路径主线程阻塞时长
    • 跨章节翻页帧稳定性
    • 预加载命中率

5.3 建议修改文件

  • Doc/TESTING.md
  • Doc/ARCHITECTURE.md
  • Sources/RDReaderView/EPUBUI/ReaderController/ChapterRuntime/RDEPUBBackgroundTrace.swift
  • 必要时新增轻量调试开关文件

5.4 验收标准

  • 有一份明确的人工回归 checklist
  • 核心链路能通过现有 Demo 手工验证
  • 关键性能/状态切换点有结构化日志

5.5 关键观测指标

Phase 0 结束前,建议至少具备以下指标:

  1. prepareOnDemandChapter 主线程 wall clock
    • 目标:识别是否仍有 UI 主路径同步等待章节构建
  2. 跨章节翻页时的帧稳定性
    • 可使用 os_signpostCADisplayLink 或简化采样方案
    • 目标:量化“动画有没有明显掉帧”
  3. RDReaderPreloadController.takePreloadedView(for:) 命中率
    • 目标:评估预加载是否真的在帮助翻页,而不是名义存在
  4. bookPageMap 扩展/替换频次
    • 目标:评估分页窗口切换是否过于频繁
  5. CFI 延迟构建次数与完成耗时
    • 目标:评估交互增强能力是否被延迟过度

6. Phase 0.5:优先消除主线程同步加载与跨章节翻页卡顿

6.1 目标

在不等待大规模结构拆分的前提下,优先解决用户感知最强的问题:

  • 跨章节翻页时主线程阻塞
  • 章节边界预加载命中不足
  • 页面进入时重复重绘开销过高

这是最高优先级阶段,目标是尽快让用户在大书场景下获得可感知的流畅度提升。

6.2 主要问题链路

当前高风险链路集中在:

  • RDEPUBReaderController+DataSource.pageContentView
  • RDEPUBReaderController+DataSource.pageNum
  • RDEPUBReaderRuntime.prepareOnDemandChapter
  • RDEPUBReaderRuntime.extendPartialBookPageMapIfNeeded
  • RDEPUBChapterLoader.loadChapterSynchronouslyForMigration
  • RDReaderPreloadController
  • RDEPUBTextPageRenderView

6.3 具体工作

  1. 将普通翻页路径上的章节准备改为异步
    • prepareOnDemandChapter 不再在 UI 主路径同步等待章节构建
    • 允许返回占位页,章节就绪后刷新当前可见内容
  2. extendPartialBookPageMapIfNeeded 改为后台批量加载
    • 不在 pageNum 回调中同步循环加载多个章节
    • 加载完成后回主线程合并 bookPageMap
  3. 前移跨章节预热
    • 用户接近章节尾页时提前 lookahead 下一章或下两章
    • 不等 pageContentView 被请求后才开始准备
  4. 调整预加载半径与策略
    • RDReaderPreloadController.radius 不再固定为章节内相邻 1 页思维
    • 预加载应感知章节边界,而不只是页号连续性
  5. RDEPUBTextPageRenderView 引入静态内容缓存
    • 避免页面进入或选区变化时重复完整 CoreText 绘制
    • 将“静态底图”和“动态选区/交互覆盖”尽量分离
  6. 明确 contentMode = .redraw 的优化策略
    • 不建议简单把 contentMode 改成缩放模式来规避重绘
    • 建议对静态文本层使用手动位图缓存,必要时再评估 CATiledLayer
    • 动态选区、高亮交互层应保持独立 overlay避免拖拽选区时重绘整页文本
  7. 为主线程阻塞建立监控
    • 重点观察跨章节翻页与恢复定位路径

6.4 建议修改文件

  • Sources/RDReaderView/EPUBUI/RDEPUBReaderController+DataSource.swift
  • Sources/RDReaderView/EPUBUI/ReaderController/RDEPUBReaderRuntime.swift
  • Sources/RDReaderView/EPUBUI/ReaderController/ChapterRuntime/RDEPUBChapterLoader.swift
  • Sources/RDReaderView/ReaderView/Paging/RDReaderPreloadController.swift
  • Sources/RDReaderView/EPUBUI/TextPage/RDEPUBTextPageRenderView.swift
  • Sources/RDReaderView/EPUBUI/TextPage/RDEPUBTextContentView.swift

6.5 阶段边界

本阶段只解决“同步改异步”和“预热/缓存前移”的问题,不强行做大规模类拆分。

也就是说:

  • 可以调整方法签名
  • 可以新增轻量状态与回调
  • 但不以“四服务化拆分 RDEPUBChapterLoader”为本阶段目标

6.6 风险点

  • 占位页策略若处理不当,可能从“卡顿”变成“短暂空白”
  • 异步章节准备如果重复触发,可能导致重复刷新和抖动
  • bookPageMap 合并时若定位恢复策略不稳定,可能引起页码闪跳

6.7 阶段验收

  • 普通翻页主路径不再依赖 UI 主线程同步章节加载
  • 跨章节翻页体感明显改善
  • 主线程阻塞监控下降到可接受水平
  • 预加载命中率比整改前提高
  • 选区拖拽时不再频繁整页重绘

7. Phase 1收缩 Context切开环境与状态

7.1 目标

把当前 RDEPUBReaderContext 从“全能对象”收缩为组合式对象,降低隐藏依赖。

7.2 改造结果

整改后至少形成三个对象:

RDEPUBReaderState

负责纯运行状态:

  • parser
  • publication
  • readingSession
  • textBook
  • bookPageMap
  • pendingFullPageMap
  • activeBookmarks
  • activeHighlights
  • searchState
  • currentSelection

RDEPUBReaderEnvironment

负责 UI 与设备环境:

  • viewport size
  • safeAreaInsets
  • traitCollection 抽象
  • brightness
  • fallbackViewportSize

RDEPUBReaderServices

负责工厂与外部依赖:

  • parser factory
  • paginator factory
  • text renderer factory
  • text builder factory
  • persistence
  • cache repository factory

7.3 具体步骤

  1. 新增文件:
    • Sources/RDReaderView/EPUBUI/ReaderController/RDEPUBReaderState.swift
    • Sources/RDReaderView/EPUBUI/ReaderController/RDEPUBReaderEnvironment.swift
    • Sources/RDReaderView/EPUBUI/ReaderController/RDEPUBReaderServices.swift
  2. RDEPUBReaderController 初始化并持有这三个对象。
  3. RDEPUBReaderContext 第一阶段暂时保留,但只作为过渡门面。
  4. 逐步把这些方法迁出 Context
    • currentLayoutContext()
    • currentTextPageSize()
    • currentTextRenderStyle()
    • currentTextLayoutConfig(pageSize:)
    • makeParser()
    • makePaginator()
    • makeTextBookBuilder(...)
  5. 移除 context.runtime 这种反向访问。
  6. 下层对象改成显式注入自己真正需要的 state/environment/services。

7.4 优先改造对象

  1. RDEPUBReaderPaginationCoordinator
  2. RDEPUBReaderLocationCoordinator
  3. RDEPUBChapterLoader
  4. RDEPUBReaderRuntime

7.5 风险点

  • 迁移过程中容易出现旧 context 和新 state/environment/services 双写。
  • 必须在阶段末关闭旧入口,否则后续会继续新增对 context 的依赖。

7.6 阶段验收

  • RDEPUBReaderContext 不再直接访问 controller.view
  • RDEPUBReaderContext 不再暴露 runtime
  • 后台线程不再通过 context 回主线程同步取分页尺寸

8. Phase 2拆分 Runtime 与章节加载编排

8.1 目标

把当前大而全的 runtime 拆成稳定的领域 facade并把章节加载逻辑从“对象内联编排”改成“服务化编排”。

8.2 拆分方向

建议把 RDEPUBReaderRuntime 拆为以下 3 类 facade

RDEPUBNavigationRuntime

负责:

  • 恢复阅读位置
  • 跳转到页码/目录/高亮/书签
  • 章节窗口维护
  • jump session

RDEPUBPresentationRuntime

负责:

  • 分页
  • bookPageMap / pendingFullPageMap
  • viewport monitor
  • settings preview
  • 当前快照替换

RDEPUBAnnotationRuntime

负责:

  • 高亮
  • 批注
  • 书签
  • 当前选区
  • 搜索结果定位联动

8.3 章节加载服务化

当前 RDEPUBChapterLoader 既做缓存命中、章节构建、磁盘写回、延迟 CFI、主线程回调。Phase 2 不建议一开始就强制拆成 4 个服务,而是建议在 Phase 0.5 完成异步化后,根据残余复杂度做渐进式收口。

优先建议的落地方式是:

  • 保留 RDEPUBChapterLoader 作为过渡门面
  • 先抽出稳定边界最清晰的构建与缓存职责
  • 把预热、lookahead、延迟 CFI、优先级调度收口到一个协调对象而不是立即拆成多个小服务

第一轮更合适的职责拆分可以是:

RDEPUBChapterBuildService

  • 输入spineIndex + render/layout context
  • 输出:RDEPUBRuntimeChapter
  • 不关心 UI、不关心回调、不关心磁盘缓存

RDEPUBChapterCacheRepository

  • 管理内存缓存与磁盘摘要缓存
  • 提供统一读写接口

RDEPUBChapterWarmupOrchestrator

  • 负责预热章节
  • 负责延迟 CFI 构建
  • 负责边界 lookahead 预取
  • 负责导航优先级、预取优先级、取消与串行化策略

如果后续复杂度继续上升,再考虑把 WarmupOrchestrator 继续拆成更细的 service但这不应作为当前阶段的先决交付物。

8.4 具体步骤

  1. 新增 facade 文件与必要的 service 文件。
  2. RDEPUBReaderRuntime 中的公共 API 先转发到新 facade。
  3. 再把具体逻辑迁走。
  4. RDEPUBChapterLoader 先收缩为过渡门面,内部优先委派到 build/cache/warmup orchestration。
  5. RDEPUBReaderRuntime 最终只保留一个薄门面,负责兼容旧调用。

8.5 风险点

  • facade 与旧 runtime 并存期较长,容易出现调用路径重复。
  • 如果服务拆分粒度过细,可能先增加调用跳转和维护成本,收益却不明显。
  • 章节加载优先级与取消策略若迁移不完整,可能引入新的页面空白或重复构建。

8.6 阶段验收

  • RDEPUBReaderRuntime.swift 行数明显下降
  • 章节加载主逻辑不再集中在单文件
  • RDEPUBReaderRuntime 不再直接操作章节缓存细节

9. Phase 3统一分页状态模型与导航状态机

9.1 目标

统一分页窗口模型,并把关键导航链路从“多个 bool/pending 值”升级为显式状态机。

9.2 要解决的问题

当前并存:

  • bookPageMap
  • pendingFullPageMap
  • chapter window snapshot
  • readingSession.activePages

这些对象都在表达“用户当前能看到什么”,只是层次不同,导致 takeover 和刷新规则分散。

9.3 目标模型

建议建立统一的分页状态对象,例如:

struct RDEPUBPaginationState {
    var activeWindow: RDEPUBPageWindow
    var candidateFullMap: RDEPUBBookPageMap?
    var chapterWindowSnapshot: RDEPUBChapterWindowSnapshot?
    var source: Source
}

配套引入状态机:

enum RDEPUBNavigationState {
    case idle
    case initialLoading
    case restoringLocation
    case preparingChapter(spineIndex: Int)
    case presentingWindow
    case reconcilingFullMap
    case repaginating
}

9.4 具体步骤

  1. 新增 RDEPUBPaginationState.swift
  2. 新增 RDEPUBNavigationStateMachine.swift
  3. 把以下逻辑统一收口:
    • applyBookPageMap
    • refreshBookPageMapInPlace
    • applyPendingFullPageMapIfNeeded
    • extendPartialBookPageMapIfNeeded
    • jump session 覆盖判断
  4. 所有页码替换、窗口扩展、完整 map takeover 都必须经过统一 evaluator。
  5. 把当前 scattered bool 收敛:
    • isRepaginating
    • didStartInitialLoad
    • isSettingsPanelOpen
    • needsFullRepaginationAfterSettingsClose

9.5 风险点

  • 这是最容易影响“当前页恢复”和“目录跳转”的阶段。
  • 必须先保留旧日志与旧行为兜底,再切换状态机入口。

9.6 阶段验收

  • 翻页、远跳、恢复位置、设置变更后 repagination 都走统一状态流
  • 不再出现多个对象各自判断“是否该替换当前窗口”
  • bookPageMap 与 snapshot 的来源关系更清晰

10. Phase 4收敛 ReaderView 抽象与模块边界

10.1 目标

RDReaderView 重新成为“通用阅读分页容器”,而不是业务与兼容逻辑混合层。

10.2 具体方向

统一 Provider 协议

对外保留:

  • RDReaderPageProvider

逐步废弃:

  • RDReaderDataSource
  • RDReaderLegacyDataSourceAdapter

拆分 ReaderView 角色

建议拆成以下内部组件:

  • RDReaderPagingSurface
  • RDReaderChromeHost
  • RDReaderInteractionRouter
  • RDReaderPreloadManager

收紧模块依赖

需要形成明确约束:

  • EPUBCore 不依赖 EPUBUI
  • EPUBTextRendering 不依赖 UIViewController
  • ReaderView 不依赖 RDEPUBReaderController
  • TextPage 只依赖页面模型与交互协议,不直接访问 controller/runtime

10.3 具体步骤

  1. 先把 RDEPUBReaderController 改成只通过 RDReaderPageProvider 对接容器。
  2. 给旧 RDReaderDataSource 增加 deprecate 注释。
  3. 把 tool view、tap routing、单双页布局决策进一步下沉到 ReaderView 内部组件。
  4. 整理 ReaderView 对业务对象的隐式假设。

10.4 风险点

  • 这是 API 层整改,最容易影响 SDK 使用方。
  • 如果已有外部方直接实现 RDReaderDataSource,需要提供过渡期。

10.5 阶段验收

  • RDEPUBReaderControllerRDReaderView 之间只通过 page provider 交互
  • RDReaderLegacyDataSourceAdapter 不再是主路径依赖
  • ReaderView 层可以被描述为“业务无关的分页容器”

11. 配套横向任务

这些任务建议穿插在各阶段中进行:

11.1 建立缓存协议层

建议新增:

  • RDEPUBPageRenderCacheKey
  • RDEPUBPageRenderCacheStore
  • RDEPUBRenderInvalidationPolicy

目标:

  • 统一字体/主题/尺寸/highlight/search 的缓存失效规则
  • 让底图缓存不再散落在 view 内部

11.2 建立定位能力层

建议新增:

  • RDEPUBTextAnchorService
  • RDEPUBSelectionLocationService
  • RDEPUBSearchAnchorService

目标:

  • 把 CFI、rangeAnchor、fragmentOffset 相关逻辑从 UI 与 text rendering 之间抽离

11.3 建立仓储接口

建议新增协议:

  • RDEPUBChapterSummaryRepository
  • RDEPUBPageCountRepository
  • RDEPUBAnnotationRepository

目标:

  • 解耦 loader 与具体缓存实现
  • 便于做测试与未来存储替换

12. 建议执行顺序

建议按以下顺序创建实施任务:

  1. phase-0-baseline-and-guardrails
  2. phase-0-5-remove-main-thread-sync-loading
  3. phase-1-context-split
  4. phase-2-runtime-and-chapter-orchestration-split
  5. phase-3-pagination-state-unification
  6. phase-4-reader-view-abstraction-cleanup
  7. horizontal-cache-and-anchor-services

原因:

  • Phase 0.5 解决最强用户痛点,且不依赖 Context 拆分。
  • Phase 1 是中期结构整改前置条件,但不是性能解阻塞前置条件。
  • Phase 2 如果先做,会继续依赖旧 context。
  • Phase 3 必须建立在 runtime 拆分之后,否则状态机会继续长进 runtime。
  • Phase 4 应该最后做,避免 UI 容器抽象在业务状态还不稳定时反复返工。

13. 每阶段交付物清单

Phase 0

  • 基线文档
  • smoke checklist
  • 日志观测点

Phase 0.5

  • 异步化的 prepareOnDemandChapter
  • 异步化的 extendPartialBookPageMapIfNeeded
  • 跨章节预热逻辑
  • 预加载半径与章节边界感知策略调整
  • RDEPUBTextPageRenderView 静态内容缓存
  • 主线程阻塞监控数据与整改前后对比

Phase 1

  • RDEPUBReaderState
  • RDEPUBReaderEnvironment
  • RDEPUBReaderServices
  • 过渡版 RDEPUBReaderContext

Phase 2

  • runtime facade 拆分
  • 渐进式的 chapter build/cache/warmup orchestration 收口
  • 过渡版 RDEPUBChapterLoader 门面
  • 旧 runtime 兼容门面

Phase 3

  • RDEPUBPaginationState
  • RDEPUBNavigationStateMachine
  • 统一 takeover/reconciliation 入口

Phase 4

  • RDReaderPageProvider 成为唯一主协议
  • ReaderView 组件化
  • 模块依赖约束文档

14. 验收口径

整改完成后,至少满足以下口径:

  1. 普通翻页、跨章节翻页、目录远跳、恢复位置不再依赖 UI 主线程同步加载章节。
  2. 下层服务不再通过 context 反向访问 controllerruntime
  3. RDEPUBReaderRuntime 不再是主要业务实现载体,而是兼容门面。
  4. 分页状态替换与窗口扩展有单一入口。
  5. RDReaderView 可以独立描述为容器层,不持有明显业务规则。

15. 不建议立即做的事

以下事项不建议在第一轮整改中做:

  1. 全量改名或移动全部文件目录。
  2. 直接重写分页系统。
  3. 直接废弃现有 readingSession
  4. 一次性删除所有旧 API。
  5. 在没有回归基线前同时推进多阶段大改。

这些操作返工风险过高,不适合当前代码体量。


16. 建议下一步

建议立即启动的实际工作是:

  1. 将本路线图拆成 6 个 phase 文档或 issue。
  2. 先执行 Phase 0。
  3. 紧接着执行 Phase 0.5,优先交付用户可感知的翻页流畅度改进。
  4. Phase 1 只做 Context 拆分,不夹带 ReaderView 或分页状态重构。
  5. 每完成一个 phase就更新 Doc/ARCHITECTURE.md

如果需要继续推进,下一份建议产物是:

  • Doc/PhasePlan/phase-0-5-remove-main-thread-sync-loading.md

它将把 Phase 0.5 再拆成更细的文件级改动清单、迁移顺序和验收步骤。