remove()和innerhtml=''在滚动中卡死页面,因其触发节点销毁、事件丢失和强制同步回流三重开销;实测200节点列表每秒滚动10次,layout时间涨3–5倍,且disconnectedcallback不保证执行,必须用dataset.id+map池化复用节点。

为什么 remove() 和 innerHTML = '' 在滚动中会卡死页面
这不是“清内存”,是主动制造性能灾难。浏览器每调用一次 remove() 或赋值 innerHTML = '',就会触发三重开销:节点树销毁、事件监听器全丢、强制同步回流(reflow)。实测在 200 节点列表上每秒滚动 10 次,layout 时间直接涨 3–5 倍;contenteditable 光标跳顶、Canvas 上下文中断、setInterval 实例泄漏都是必然结果。
更隐蔽的是:disconnectedCallback 不保证执行——页面切后台、刷新、崩溃时它根本不会被调用,指望生命周期自动清理等于把稳定性交给随机性。
-
remove()后再appendChild()已存在节点,connectedCallback不会再次触发 -
innerHTML = ''清空后,第三方插件(如代码高亮、富文本)实例彻底丢失,重建成本远高于复用 - 用数组缓存节点?滚动中索引漂移(比如 splice 删除中间项)会导致数据与 DOM 错位
必须用 dataset.id + Map 做节点池化,不能用 class 或索引
节点复用不是“存起来再拿出来”,而是“擦写复用”:只隐藏、只更新可变字段,结构和绑定全保留。关键前提是每个节点初始化就必须带稳定、全局唯一的 dataset.id(如 item-001),不能靠 index 动态生成——滚动中索引会变,但 id 必须恒定。
结构也必须固化:class 名、子元素层级、插槽位置都不能在复用时增删。禁止在复用逻辑里调用 appendChild()、innerHTML = '' 或修改 className。
- 缓存容器必须用
Map,不用数组——避免索引漂移导致渲染错位 - 回收前检查
node.dataset.id && !nodePool.has(node.dataset.id),防重复存入同一节点 - 复用时先
nodePool.delete(id),再返回节点,防止异步场景下被重复取出 -
recycleNode()只设node.style.display = 'none',不调removeChild()
瀑布流 JS 实现中列高维护和图片预加载的硬约束
CSS column-count 无法用于真实瀑布流加载,因为它按文档流顺序切片,不暴露列高,也无法控制插入位置。JS 方案必须维护一个列高数组,并每次找最小高度列追加新项——但这不是难点,难点在于“怎么让这个数组始终可信”。
列容器必须是独立 <div> 元素(如 <code><div class="col" id="col-0"></div>),不能用 position: absolute 模拟,否则 offsetHeight 取不到真实值。图片原始尺寸未知时,不能直接读 img.height,得用 new Image() 预加载,拿到 naturalWidth/naturalHeight 后再等比缩放算渲染高度。
- 滚动加载新图时,列高数组不能重置,必须在已有基础上继续找最小列
- 裸
<img>不支持break-inside: avoid,必须用position: relative的 wrapper 包一层 - Firefox/Safari 下需额外补丁:
-webkit-column-break-inside: avoid、统一min-height或用aspect-ratio预留空间
微信小程序里 setData 和节点复用的双重枷锁
小程序不是 Web 页面,逻辑层和渲染层分离,每一次 setData 都要跨线程序列化传输。瀑布流无限加载若不做节制,几十个复杂卡片一塞,内存很快触顶闪退——尤其 iOS 上更敏感。
这里没有 DOM 池化概念,但有等效策略:WXML 节点不能删,只能 hide/show;data 层要拆分,把“可见区数据”和“全量缓存”分开管理;图片必须预加载+占位+解码优化,否则 CPU 解码会直接拖垮帧率。
- 避免在 scroll 回调里高频调用
setData,改用节流或 IntersectionObserver 触发 - 图片加载完成前用
aspect-ratio或固定min-height占位,防布局抖动 - WXML 中每个
<view></view>必须带唯一id或data-id,复用时只更新绑定字段,不重建结构
真正卡住性能的,从来不是“怎么加新内容”,而是“怎么不动旧节点”。所有看似省事的删、清、重 render,最终都变成 layout 压力、事件丢失、内存泄漏的温床。稳定 id、固定结构、只更新字段——这三条,漏一条,滚动就崩一半。











