vue 2 项目下 页面内存过高问题排查记录

起因是用户反馈网页操作久了后,页面会出现白屏情况。 项目主要包版本:

  • vue-cli4
  • vue2.6
  • element-ui 2.15

解决白屏问题

复现过程中发现页面刷新后,详情页面的路由点击都变成了白屏。

排查过程中发现:

  • 这是正常情况的详情路由
  • 页面刷新后变成了 原因:页面刷新后,所有会被路由清空,重新进入页面时会重新请求菜单数据追加路由。但是详情路由并不是从后端获取的,而是在后续操作过程中新加入的,所以刷新后数据丢失了,路由找不到,才会白屏。

解决思路:

将路由缓存下来,这样页面刷新后先读取缓存数据。解决过程中发现,我们的 tab 标签数据【这个数据里面有当前路由对应的组件地址】是有缓存的,那么我们就可以给后加入的路由一个标志,初始化路由的时候,看看有没有缓存的 追加的 tab 数据,有就拼接路由。

白屏解决,刷新后页面,详情页面恢复。

解决页面崩溃问题

解决了白屏问题后,用户反馈,详情页面自己修改操作的一些数据又没有了,有时候页面还出现了崩溃现象。一番挣扎后发现,都是页面内存占用过高惹的祸。主要的占用就是el-table 引起的,现象:

  1. 表格数量多,表格内部结构复杂
  2. 用户老喜欢一次性查询1000条数据
  3. 后端返回的数据体积超大,10M起

主要的影响因素

排查思路:

  1. 表格数据是否回收
  2. el-dialog 数据是否回收
  3. keep-alive 移除后数据时候回收

表格数据回收问题

表格数据清空后,Detached <div>中出现了大量的el-popover元素。查阅一番发现,vue中模态框就会出现内存泄漏问题。而我们的表格中,每一行基本都有n个el-popover,那整个表格不就是1000n个。而且popover会产生大量的真实dom,会对页面渲染造成卡吨。既然已经要泄漏了,那么就将泄漏1000n变成1个吧。

解决方向: 表格所有需要触发popover的元素都共用一个popover。

  1. 改造现有el-popover,我们直接使用 v-if 还是会造成内存泄漏,所以使用组件内部的方法去销毁他。使用继承是方便直接使用里面的属性、方法。
vue 复制代码
<script>
import { Popover } from "element-ui"; // 引入element的popover组件
import Vue from "vue"; // 引入vue
export default Vue.extend({ // Vue.extend是vue中的api,用于继承组件
  extends: Popover, // 指定要继承的组件
  methods: {
    popBy(el) {
      // 先隐藏并销毁之前显示的
      this.close();
      this.doDestroy(true);
      this.$nextTick(() => {
        // 显示新的 referenceElm 是触发显示popover的元素
        this.referenceElm = this.$refs.reference = el;
        this.$nextTick(() => {
          this.showPopper = true;
          this.$emit("input", true);
        });
      });
    },
    close() {
      this.showPopper = false;
      this.$emit("input", false);
    }
  }

});
</script>
  1. customPop使用
xml 复制代码
<template>
  <customPop
    ref="popoverRef"
    popper-class="table-item-popover"
    placement="top"
    width="542"
    @show = "show"
    @hide = "hide"
  >
    <!-- popover 展示内容 -->
  </customPop>
</template>
<script>
import customPop from "./../../../../customPop";
export default {
  name: "tablePopover",
  components: {  customPop },
  data() {
    return {
      showPop: false,
  
    };
  },
  methods: {
    open(e, content) {
      this.showPop = true;//便于判断popover 是否打开
      this.$refs.popoverRef.popBy(e);
    },
    show() {
      // 需要赋值的逻辑在这个处理 customPop会先销魂再创建 popover的hide会在打开后出发一次
    },
    close() {
      this.$refs?.popoverRef?.close();
    },
    hide() {
      // 将动态创建的dom 都清除
      this.showPop = false;
      this.relationFormGroups = [];
    },
    destory() {
      try {
        this.$refs?.popoverRef?.doDestroy(true);
      } catch (e) {
        console.error("表格popover", e);
      }
    }
  },
  beforeDestroy() {
    this.destory();
  }
};
</script>
  1. 表格统一调用
vue 复制代码
<tempalte>

 <tablePopover ref="tablePopover"/>
</template>
<script>
export default{
    data(){
    popel:null
    },
 methods:{
     openPover(e){
     if(this.popel===e.target){//同一元素不触发
     
         return;
     }
        this.$refs['tablePopover']?.open(e.target);
    }
 }
 
}
</script>
  1. 效果 1000千数据共32M,内存占用1.9G降低至1.35G。如果可以的话,把tableData也就是表格数据用Object.freez()冻结,内存能再降低一些。

el-dialog 回收问题。

el-dialog 也是模态框所以也会有会内存泄漏问题,这个问题目前没有找到比较好的根本解决方法。缓解方法就是将动态渲染出来的dom,在弹框关闭时先将数据清空然后再关闭。

keep-alive 移除问题

测试发现,表格加载页面后,如果页面没有出现dom更新,也就页面没有出现过新的元素,如输入框输入内容,打开弹框等,关闭后就能回收,表格也不会泄漏。但是一旦有元素变化,那表格内容就都泄漏了。但是如果重新回到关闭的那个页面,内存的泄漏又会减少。目前还没有很好的解决方法。

相关推荐
颜酱12 分钟前
理解并尝试vue3源码的reactivity
前端·javascript·vue.js
苏州第一深情19 分钟前
【uniapp】uniapp实现单点登录、打包H5部署到线上
javascript·vue.js·uni-app
chxii36 分钟前
2.4 组件通信
前端·javascript·vue.js
天神下凡_1 小时前
前端解析markdown语法
前端·vue.js
用户500248498061 小时前
vue中的ref属性与nextTick
vue.js
王者鳜錸2 小时前
VUE+SPRINGBOOT从0-1打造前后端-前后台系统-登录实现
前端·vue.js·spring boot
Yanc4 小时前
翻了vue源码 终于解决了这个在SFC中使用tsx的bug
前端·vue.js
萌萌哒草头将军4 小时前
VoidZero 发布消息称 Vite 纪录片即将首映!🎉🎉🎉
javascript·vue.js·vite
好好好明天会更好4 小时前
那些关于$event在vue中不得不说的事
前端·vue.js