引言
本技术文档面向 DouPHP 小程序的性能优化,聚焦页面渲染、网络请求、内存管理三大维度,并结合仓库中实际实现给出可落地的方案:图片懒加载、组件按需加载、路由延迟加载、本地/接口/计算结果缓存、对象池与事件清理、大对象处理、以及性能监控与问题定位方法。文档以代码级为依据,提供流程图与时序图帮助理解数据流与控制流,并给出实战调优建议。
项目结构
DouPHP 小程序位于 miniprogram/default 目录,采用“应用入口 + 服务层 + Store(状态)+ 工具 + 页面”的分层组织:
- 应用入口 app.ts:注册全局 HTTP 拦截器、引导 Store 水合、自动更新、错误钩子等。
- 服务层 services/http.ts:统一 HTTP 封装,包含信封解析、去重、内存缓存、调试增强。
- 状态层 stores/*:MobX 驱动的 store 聚合与持久化(persist.ts)。
- 工具 utils/*:命名路由生成、环境判断、UI 辅助等。
- 页面 pages/*:业务页面,如首页 index 使用 Store 与 http 进行数据获取与渲染。
graph TB
A["app.ts<br/>应用启动"] --> B["stores/index.ts<br/>Store 聚合与引导"]
B --> C["services/http.ts<br/>HTTP 封装"]
B --> D["stores/persist.ts<br/>本地持久化"]
A --> E["utils/route.ts<br/>命名路由"]
F["pages/index/index.ts<br/>首页"] --> C
F --> B
F --> E
图示来源
- miniprogram/default/app.ts:12-62
- miniprogram/default/stores/index.ts:44-60
- miniprogram/default/services/http.ts:194-339
- miniprogram/default/stores/persist.ts:19-59
- miniprogram/default/utils/route.ts:21-65
- miniprogram/default/pages/index/index.ts:29-57
章节来源
- miniprogram/default/app.ts:12-62
- miniprogram/default/stores/index.ts:44-60
- miniprogram/default/services/http.ts:194-339
- miniprogram/default/stores/persist.ts:19-59
- miniprogram/default/utils/route.ts:21-65
- miniprogram/default/pages/index/index.ts:29-57
核心组件
- 应用启动与全局异常处理:在 onLaunch 中注册 HTTP 错误拦截、推广参数解析、窗口尺寸计算、自动更新、调试开关;onError/onUnhandledRejection/onPageNotFound 提供统一错误上报与调试提示。
- HTTP 层:统一信封解析、默认头注入、请求/成功/失败拦截器、GET 去重、内存缓存(带 TTL)、request_id 追踪、调试弹窗。
- Store 聚合与持久化:先 hydrate(storage 秒开),再 refresh/restore(网络刷新),cart 角标绑定;持久化通过 schema_version 控制失效。
- 命名路由:集中式路由表生成 URL,支持 rewrite_enable 回退模式。
- 首页示例:使用 Store 字段绑定、http 拉取数据、分页触底追加、分类滚动进度条计算。
章节来源
- miniprogram/default/app.ts:23-96
- miniprogram/default/services/http.ts:194-339
- miniprogram/default/stores/index.ts:44-60
- miniprogram/default/stores/persist.ts:19-59
- miniprogram/default/utils/route.ts:21-65
- miniprogram/default/pages/index/index.ts:29-57
架构总览
小程序运行时的关键路径:App 启动 -> Store 水合与刷新 -> 页面发起请求 -> HTTP 层缓存/去重 -> 返回数据驱动 UI。
sequenceDiagram
participant App as "app.ts"
participant Stores as "stores/index.ts"
participant Persist as "stores/persist.ts"
participant Page as "pages/index/index.ts"
participant Http as "services/http.ts"
participant WX as "wx.request"
App->>Stores : bootstrapStores()
Stores->>Persist : hydrate (loadPersisted)
Stores->>Stores : refresh / restore
Page->>Http : get(route('index'))
Http->>Http : 检查内存缓存/去重
Http->>WX : 发起网络请求
WX-->>Http : 响应体
Http->>Http : 解析信封/附加元信息
Http-->>Page : data<T>
Page->>Page : setData 更新视图
图示来源
- miniprogram/default/app.ts:23-62
- miniprogram/default/stores/index.ts:44-60
- miniprogram/default/stores/persist.ts:19-59
- miniprogram/default/pages/index/index.ts:29-57
- miniprogram/default/services/http.ts:194-339
详细组件分析
应用启动与全局错误处理(app.ts)
- 职责:初始化全局状态、注册 HTTP 错误拦截、解析推广参数、计算导航栏高度、自动更新、开启调试。
- 性能要点:
- 将耗时操作(如网络刷新)放在 bootstrapStores 中异步执行,避免阻塞冷启动。
- 仅在调试环境启用 vConsole 与错误弹窗,减少生产开销。
- 推广参数解析在 onLaunch/onShow 两处执行,确保卡片打开场景也能正确写入 storage。
flowchart TD
Start(["App.onLaunch"]) --> Init["注册 HTTP 错误拦截"]
Init --> ParsePromo["解析推广 user_sn 并写入 storage"]
ParsePromo --> Hydrate["bootstrapStores() 水合 Store"]
Hydrate --> Measure["计算窗口/导航栏高度"]
Measure --> AutoUpdate{"是否可更新?"}
AutoUpdate --> |是| UpdateFlow["检查并提示更新"]
AutoUpdate --> |否| DebugCheck{"是否调试环境?"}
DebugCheck --> |是| EnableDebug["开启 vConsole"]
DebugCheck --> |否| End(["完成"])
图示来源
- miniprogram/default/app.ts:23-62
- miniprogram/default/app.ts:131-156
章节来源
- miniprogram/default/app.ts:23-96
- miniprogram/default/app.ts:131-156
HTTP 层封装(services/http.ts)
- 职责:标准信封解析、默认头注入、拦截器机制、GET 去重、内存缓存(TTL)、调试增强(request_id、堆栈弹窗)。
- 性能要点:
- GET 去重:相同 key 的并发请求复用 Promise,降低重复网络开销。
- 内存缓存:命中且未过期直接返回,适合热点配置或静态列表。
- 不可枚举元信息:为 data 附加 message/request_id,避免序列化到 setData,减少传输体积。
- 调试期弹栈:仅开发环境弹出服务端异常详情,生产不增加额外成本。
flowchart TD
Req["request(config, opts)"] --> CheckCache{"opts.cache 且未过期?"}
CheckCache --> |是| ReturnCache["返回内存缓存"]
CheckCache --> |否| Dedupe{"GET 且 inflight[key]?"}
Dedupe --> |是| ReturnDup["复用飞行中的 Promise"]
Dedupe --> |否| WxReq["wx.request 发起请求"]
WxReq --> Parse["解析信封 code/message/data/errors/request_id"]
Parse --> Ok{"code === 'OK' ?"}
Ok --> |否| Err["构造 ApiError 并触发错误拦截器"]
Ok --> |是| Attach["附加不可枚举元信息"]
Attach --> CacheWrite{"opts.cache ?"}
CacheWrite --> |是| Write["写入 memoryCache(key, ttl)"]
CacheWrite --> |否| Skip["跳过缓存"]
Write --> Resolve["resolve(data)"]
Skip --> Resolve
Err --> Reject["reject(ApiError)"]
图示来源
- miniprogram/default/services/http.ts:194-339
章节来源
- miniprogram/default/services/http.ts:194-339
Store 聚合与持久化(stores/index.ts, stores/persist.ts)
- 职责:聚合 common/auth/cart Store,先 hydrate 再 refresh/restore;cart 角标由 autorun 驱动;持久化带 schema_version 控制失效。
- 性能要点:
- 冷启动秒开:优先从 storage 恢复状态,再异步刷新网络数据,提升首屏体验。
- 版本化失效:SCHEMA_VERSION 变更时旧缓存自动丢弃,避免脏数据。
- 角标联动:autorun 监听 cart.badge 变化,统一 set/remove 角标,减少重复调用。
classDiagram
class StoreIndex {
+bootstrapStores()
+bindCartBadge()
}
class Persist {
+loadPersisted(key) T|null
+savePersisted(key, data) void
+clearPersisted(key) void
+persistAutorun(key, selector) disposer
}
StoreIndex --> Persist : "hydrate/restore"
图示来源
- miniprogram/default/stores/index.ts:44-60
- miniprogram/default/stores/persist.ts:19-59
章节来源
- miniprogram/default/stores/index.ts:44-60
- miniprogram/default/stores/persist.ts:19-59
命名路由(utils/route.ts)
- 职责:根据后端生成的路由表构建前端 URL,支持占位符替换与 query 拼接,rewrite_enable 决定最终形态。
- 性能要点:
- 集中式路由表,避免硬编码路径,便于维护与 SEO。
- 空值过滤与多余斜杠清理,减少无效字符带来的解析开销。
章节来源
- miniprogram/default/utils/route.ts:21-65
首页示例(pages/index/index.ts)
- 职责:展示站点信息与商品列表,支持分类横滑进度条、触底分页加载。
- 性能要点:
- 使用 Store 字段绑定减少 setData 粒度,提高渲染效率。
- 触底延迟加载(setTimeout 1s)避免频繁请求。
- 分类滚动状态缓存视口与内容宽度,减少重复查询。
章节来源
- miniprogram/default/pages/index/index.ts:29-57
- miniprogram/default/pages/index/index.ts:127-175
- miniprogram/default/pages/index/index.ts:81-125
依赖关系分析
- app.ts 依赖 stores/index.ts 进行状态引导,依赖 services/http.ts 注册错误拦截。
- stores/index.ts 依赖 stores/persist.ts 进行持久化读写,依赖 utils/tabbar.js(外部)进行角标索引解析。
- pages/index/index.ts 依赖 services/http.ts、stores/index.ts、utils/route.ts 完成数据获取与路由跳转。
- services/http.ts 依赖 wx.request 与 utils/env.js(外部)进行调试开关判断。
graph LR
App["app.ts"] --> Stores["stores/index.ts"]
App --> Http["services/http.ts"]
Stores --> Persist["stores/persist.ts"]
Page["pages/index/index.ts"] --> Http
Page --> Stores
Page --> Route["utils/route.ts"]
图示来源
- miniprogram/default/app.ts:12-62
- miniprogram/default/stores/index.ts:44-60
- miniprogram/default/stores/persist.ts:19-59
- miniprogram/default/pages/index/index.ts:29-57
- miniprogram/default/utils/route.ts:21-65
- miniprogram/default/services/http.ts:194-339
章节来源
- miniprogram/default/app.ts:12-62
- miniprogram/default/stores/index.ts:44-60
- miniprogram/default/stores/persist.ts:19-59
- miniprogram/default/pages/index/index.ts:29-57
- miniprogram/default/utils/route.ts:21-65
- miniprogram/default/services/http.ts:194-339
性能考量
- 页面渲染性能
- 使用 Store 字段绑定与最小化 setData,避免全量更新导致重绘。
- 列表分页触底加载,结合节流/防抖减少频繁交互。
- 分类滚动状态缓存视口与内容宽度,减少布局查询次数。
- 网络请求优化
- GET 去重:同一 key 的并发请求复用 Promise,降低服务器压力。
- 内存缓存:对热点数据设置 TTL,命中即返回,减少网络往返。
- 不可枚举元信息:避免序列化到 setData,减小数据体积。
- 统一信封解析:标准化错误处理,减少分支逻辑复杂度。
- 内存管理最佳实践
- 对象池:对于高频创建销毁的对象(如图片占位、临时数组),可在页面生命周期内复用,减少 GC 压力。
- 事件监听清理:页面卸载时解除事件绑定与定时器,避免内存泄漏(例如 onUnload 中 destroyStoreBindings)。
- 大对象处理:分页加载、虚拟列表、按需渲染,避免一次性加载过多数据。
- 懒加载技术
- 图片懒加载:使用 IntersectionObserver 或 scroll 事件检测可视区域,延迟加载非首屏图片。
- 组件按需加载:使用 wx.importObject 或分包加载,减少主包体积。
- 路由延迟加载:对非首屏路由使用懒加载策略,进入页面时再加载资源。
- 缓存策略
- 本地缓存:使用 persist.ts 的 load/save/clear 接口,配合 schema_version 控制失效。
- 接口缓存:http.ts 的内存缓存与 TTL,适合短时效热点数据。
- 计算结果缓存:对复杂计算结果进行 memoization,避免重复计算。
- 性能监控与分析
- request_id 追踪:每个请求附带唯一标识,便于与服务端日志对照定位问题。
- 调试弹窗:开发环境弹出服务端异常堆栈,快速定位问题。
- 指标收集:记录首屏时间、接口耗时、缓存命中率等指标,评估优化效果。
故障排查指南
- 常见问题
- 接口报错:查看 ApiError.code 与 message,结合 request_id 在服务端定位。
- 缓存命中异常:检查 memoryCache 的 key 与 TTL,必要时 clearCache。
- 页面崩溃:关注 onError/onUnhandledRejection 日志,调试环境可弹出 modal 查看详情。
- 定位步骤
- 使用 getLastRequestId 获取最近一次请求的 request_id,与服务端日志对照。
- 在 isDebugEnv 环境下启用 vConsole,观察控制台输出。
- 对可疑请求添加 console.log 或断点,确认数据流与状态变化。
章节来源
- miniprogram/default/services/http.ts:133-175
- miniprogram/default/services/http.ts:366-379
- miniprogram/default/app.ts:69-96
结论
DouPHP 小程序通过统一的 HTTP 层、Store 聚合与持久化、命名路由与页面分层,构建了高效、可维护的前端架构。结合内存缓存、GET 去重、Schema 版本化失效、调试增强等手段,显著提升了冷启动速度与网络效率。建议在后续迭代中持续引入图片懒加载、组件按需加载、路由延迟加载等优化手段,并完善性能监控体系,形成闭环优化流程。
附录
- 术语解释
- 信封:API 响应的标准结构,包含 code/message/data/errors/request_id。
- 水合:从本地存储恢复状态,实现秒开。
- 去重:相同请求合并,避免重复网络调用。
- 参考实现路径
- HTTP 层:miniprogram/default/services/http.ts
- Store 持久化:miniprogram/default/stores/persist.ts
- 应用启动:miniprogram/default/app.ts
- 命名路由:miniprogram/default/utils/route.ts
- 首页示例:miniprogram/default/pages/index/index.ts