前端入门到弃坑:10000条数据怎么优化

我是歌谣 放弃很容易 但是坚持一定很酷 微信公众号关注前端小歌谣 带你进入巅峰前端交流群

前言

最近没啥项目做,闲着无聊,写写文档解解闷。

也许看到这标题的时候,开发肯定想捶提供数据的后台小哥,数据量这么大,就不能做下分页在返回嚒。直接渲染到页面会引起页面的卡顿,白屏时间过长会造成用户的流失。虽然心中有无数匹马在狂奔,但是在一些场景下,还是有可能你拿到的数据就是这样的。

正文

提出问题:

1、十万条数据要如何进行处理?

2、直接渲染页面会造成什么问题?

3、如何提升整体页面的操作性能?

解决方案:

分页 + 懒加载 + 防抖函数

话不多说,先造个demo先,demo如下:

上面显示毫秒分别是造数据花费的时间和页面未渲染数据所花费的时间,方便后续统计优化前后的区别。

首先我们要先造测试数据,code如下:

createData() {
      this.userList = [];
      for (let i = 0; i < 100000; i++) {
        ((i) => {
          let user = {
            name: "用户" + (i + 1),
            date: this.renderTime(),
            sex: this.sex(i),
          };
          this.userList.push(user);
          if (!i) {
            this.dataTimeStart = new Date().getTime();
          }
          if (i == 99999) {
            this.dataTimeEnd = new Date().getTime();
            this.dataTemp = this.dataTimeEnd - this.dataTimeStart;
          }
        })(i);
      }
      this.cloneLIst = JSON.parse(JSON.stringify(this.userList));
      this.userList = [];
      this.total = this.cloneLIst.length;
    },

先看下未分页直接渲染页面会有啥影响,如下:

从上面的视频可以看到直接往页面插入十万条数据并渲染,会造成页面卡顿以及白屏,页面性能极低。

渲染完成的时间也从31ms变成了40576ms

实现对数据的分页,code如下:

definePage() {
      this.loading = true;
      let newArr = [];
      let len = this.total;
      let n = this.size; // 每页多少条
      let lineNum = len % 4 === 0 ? len / 4 : Math.floor(len / 4 + 1);
      for (let i = 0; i < lineNum; i++) {
        let temp = this.cloneLIst.slice(i * n, i * n + n);
        newArr.push(temp);
      }
      newArr = newArr.filter((item) => {
        return item.length;
      });
      this.userList = newArr[this.page - 1];
      setTimeout(() => {
        this.loading = false;
      }, 500);
    },

然后我们在来看下分页后的效果,如下:

很明显分页后页面流畅了好多,渲染速度也快了好多。

引入滚动插件,监听页面滚动距离,加载数据,code如下:

<!-- 引入滚动插件 -->
    <div class="test-wrap-scroll">
      <el-input
        style="width: 240px"
        placeholder="请输入性别"
        v-model="keyWords"
        @keyup.native.enter="query"
        clearable
      ></el-input>
      <div class="test-wrap-scroll__head">
        <span>姓名</span>
        <span>生日</span>
        <span>性别</span>
      </div>
      <ul class="test-wrap-scroll__ul" v-infinite-scroll="userLoad">
        <li
          v-for="(item, key) in userList"
          class="infinite-list-item"
          :key="key"
        >
          <span>{{ item.name }}</span>
          <span>{{ item.date }}</span>
          <span>{{ item.sex }}</span>
        </li>
      </ul>
    </div>

//自定义分页
definePage() {
      this.loading = true;
      let newArr = [];
      let len = this.total;
      let n = this.size; // 每页多少条
      let lineNum = len % 4 === 0 ? len / 4 : Math.floor(len / 4 + 1);
      for (let i = 0; i < lineNum; i++) {
        let temp = this.cloneLIst.slice(i * n, i * n + n);
        newArr.push(temp);
      }
      newArr = newArr.filter((item) => {
        return item.length;
      });
      // this.userList = newArr[this.page - 1];//替换成下面插入数据方式
      this.userList = [...this.userList, ...newArr[this.page - 1]];
      setTimeout(() => {
        this.loading = false;
        this.tag = '';
      }, 500);
    },

//监听滚动event
userLoad() {
      if(this.tag) return;
      this.page++;
      this.definePage();
    },

效果如下:

可以看出页面非常流畅,这里我用的是饿了么自带的无限滚动组件。要是想用JavaScript监听页面滚动,可以使用window.scroll方法,判断页面滚动的距离到一定范围内加载数据,输入框查询使用防抖函数筛选重新插入数据。

防抖函数如下:

debounce(fn, time) {
    return function(args) {
      let that = this
      clearTimeout(fn.tid)
      fn.tid = setTimeout(() => {
        fn.call(that, args)
      }, time);
    }
  }

查询函数如下:

注:查询会触发滚动事件,所以这里我使用tag标记正在loading中,防止页面抖动连续插入数据。

query() {
      this.page = 1;
      this.createData();
      this.tag = 'loading'
      if (this.keyWords) {
        this.cloneLIst = this.cloneLIst.filter((item) => {
          let judge = ["sex"].find((i) => {
            return item[i].includes(this.keyWords);
          });
          return judge ? item : false;
        });
      }
      if(this.cloneLIst.length) {
          this.definePage();
      }
    },

效果如下:

上面的案例是在vue环境下实现的,那如果想以操作dom的方式,往页面插入dom,可以使用window自带的动画api(requestAnimationFrame),告诉浏览器接下来的操作是一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。

浏览器绘制每一帧,都会按照以下过程进行:

1、开始新的一帧率

2、处理输入事件

3、执行requestAnimationFrame

4、解析html

5、计算样式

6、更新图层树

7、发送帧

执行最后一帧的时候,可以通过cancelAnimationFrame,不要继续执行requestAnimationFrame回调了。

原文链接:https://zhuanlan.zhihu.com/p/505873741

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值