Skip to content

运行时还可以做哪些优化? ​

高频事件先节流或防抖,纯计算能缓存就缓存,长任务移出主线程或拆开。这些手段都建立在「已经测量过瓶颈」之上,不作为默认写法。

原理 ​

滚动、缩放、拖拽用节流,保证一段时间里至少更新一次。搜索框用防抖,等输入停下来再请求。见 防抖与节流 和 搜索与请求竞态。

同一份输入会反复算出同一个结果时,把结果存起来。缓存要有上限,否则闭包或 Map 会一直涨。组件里优先让派生数据在渲染时计算;只有测量到这段计算明显占时间,再用 useMemo 或 Vue 的 computed。

主线程要解析、执行、布局和响应输入。大文件解析、复杂diff可以放进 Web Worker,主线程只接收结果。Worker 没有 DOM,传大数据时优先用可转移的对象,避免复制。

长任务还可以切成小段:处理一批条目后 await 一个 scheduler.yield(),或先让出到宏任务,让浏览器有机会绘制和响应点击。用户正在输入时,用过渡更新把重活标成可打断。

同步的 localStorage 和巨大的 JSON 解析会卡住交互。大缓存放 IndexedDB,读取放在用到之前的空闲时间。

追问 ​

防抖会不会让界面发黏?

按钮点击的反馈不要防抖。防抖的是请求或重计算。界面上的按下状态应该同步发生。滚动位置如果也等防抖,会明显落后于手指,所以滚动用节流或者直接跟 requestAnimationFrame。

缓存键怎么设计?

键必须能代表全部输入。漏了一个过滤条件,就会返回别人的结果。对象当键要先规范化,否则每次新对象都命不中。

易错点 ​

  • 没测量就给所有计算加缓存,缓存查找和依赖比较可能更贵。
  • Worker 的创建和通信有成本,几毫秒的计算不值得搬过去。
  • 节流函数如果保存了 DOM 节点或大对象,组件卸载时要 cancel,否则定时器继续持有它们。

相关 ​