Skip to content

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 在当前页面场景下过重,抬高了页面整体渲染成本,最终把输入框这种轻交互也拖慢了。


一句话总结

这次卡顿的本质,不是“主线程一直没释放”,而是页面整体渲染成本被重组件抬高,导致连输入框这种轻交互也被拖慢。