js 页面输入框输入卡顿
场景
- web页面内嵌electron webview中,
- 页面表格加载过多30+的数据之后,
- 当扫描一次输入框之后,间隔很久,扫描第二次卡顿
- 本质就是主线程没有释放
原因分析
1. 异步流程没有严格串行
- 代码里异步链不够严格串行,会放大问题
- 但这不是主要原因
2. 扫码成功后的副作用较多
- 扫码成功后会触发表格、状态、分页等更新
- 页面一旦进入“更重状态”,后续输入持续受影响
- 这是一个表面线索
3. keyField 配置错误(重要原因)
旧配置:
:row-config="{ keyField: 'id' }"
但返回数据中没有 id 字段,导致:
- 行拿不到有效唯一标识
- 行身份识别退化
- 内部依赖
rowid的状态映射更容易失真或退化 - 增加主线程同步工作
修正为真实存在的字段后,例如:
:row-config="{ keyField: 'name' }"
在 30+ 条数据 时,卡顿明显缓解。
说明 keyField 配置错误是重要原因。
4. vxe-table 本身的性能瓶颈(核心原因)
继续测试发现:
- 修正
keyField后,30+ 数据不再明显卡顿 - 但数据到 80+ 时,页面依然卡顿
- 同样数据改用
el-table后,不再明显卡顿
5、为什么数据多了,vxe-table性能就拖累了浏览器
一个大表格组件:
- 节点密集
- 行列结构复杂
- 宽高、滚动、对齐要求高
- 很容易触发布局计算
- 数据更新时影响面大
- 那它虽然只是页面的一部分,但它触发的可能是:
- 一大片区域重算样式
- 一大片区域重排
- 一大片区域重绘
- 企业级的表格
- 内部状态维护
- 行标识映射
- 当前行、hover、选中态
- 滚动区同步
- 列宽处理
- 虚拟滚动相关逻辑
- 本质
- 一个重组件,让浏览器和主线程都处于高负载状态,那么即使输入框自己很轻,它也会被拖累。
- 页面设计触发了浏览器最昂贵的工作模式。
- 浏览器不是在“执行一个组件”,而是在维护一个活的页面系统。
解决方案
1、vxe-table 开启虚拟滚动
html
<!--
enabled:显式开启纵向虚拟滚动
gt:行数超过 20,启用纵向虚拟
oSize:额外渲染的缓冲行数,别设太大。一般 10~20 先试。
-->
<vxe-table
:data="data"
:row-config="{ keyField: 'name' }"
:scroll-y="{ enabled: true, gt: 20, oSize: 10 }"
>
<vxe-table-column
v-for="item in columns"
:key="item.field"
align="center"
:field="item.field"
:title="item.title"
:width="item.width"
/>
</vxe-table>2、使用 el-table 替代
html
<!-- 数据80+ 不卡顿 -->
<el-table :data="data">
<el-table-column
v-for="item in columns"
:prop="item.prop"
:label="item.label"
:width="item.width">
</el-table-column>
</el-table>要点
- 1、在 Chromium / Electron 渲染进程里,JS 执行、输入事件处理、布局和绘制是强相关的,当主线程一直忙于跑 JS、处理事件、执行回调时,浏览器就拿不到足够空档去完成下一轮渲染更新
- 2、重组件导致的卡顿,不只是组件自身代码执行慢,而是它触发并维持了浏览器中昂贵的样式计算、布局、绘制和主线程更新链路,从而把整个页面带入持续性高成本状态,最终连输入框这种轻交互也会被拖慢。
总结
1. 之前的判断:主线程没有释放
前面一度把问题理解成:
上一次操作还没结束,主线程一直没有释放,所以后续输入被卡住了。
这个判断抓住了现象,但不是最终根因。
因为后面已经验证到:
- 等了很久,输入仍然卡
- 不回车、不触发表格更新,单纯在输入框里持续输入也卡
- 说明不是某一次异步任务还没结束,也不是某个同步任务一直在执行
2. 更准确的根因:页面渲染成本变得过高
真正的问题是:
页面进入了持续性的高成本渲染状态。
也就是说,不是“主线程一直没释放”,而是:
- 页面里某个重组件把整体渲染/布局环境拖重了
- 后续任何小交互,都要在这个更重的页面环境里完成
- 即使只是一个普通输入框输入一个字符,也要付出更高的处理和绘制成本
所以最后表现为:
- 输入框字符一截一截显示
- 普通键盘输入也发沉
- 页面像“用久了变慢”一样
3. 为什么输入框会被拖慢
输入框本身并不重,但输入一个字符时,浏览器仍然要做:
- 输入事件处理
- input 值更新
- 光标/caret 更新
- 样式计算
- 局部布局和绘制
如果页面整体已经被重组件拖进高成本状态,那么:
输入框虽然很轻,但它也必须运行在这个高成本页面里,所以同样会被拖慢。
4. 最终落点
这次问题最终不是:
- 输入框本身有问题
- 某个异步一直没结束
- 某个函数一直占着主线程
而是:
vxe-table在当前页面场景下过重,抬高了页面整体渲染成本,最终把输入框这种轻交互也拖慢了。
一句话总结
这次卡顿的本质,不是“主线程一直没释放”,而是页面整体渲染成本被重组件抬高,导致连输入框这种轻交互也被拖慢。