Uniapp中要实现一次性加载10000条数据渲染问题

721 阅读3分钟

性能优化问题

在八股文面试过程中会被经常问到如果有十几万条数据如何处理?

  **分页加载:** 不要一次性加载和渲染1000条数据,而是将数据分成多个页面或分页加载。只加载并显示当前页面或滚动视图中可见的部分数据。用户可以滚动或翻页来查看更多数据。
  **虚拟滚动:** 使用虚拟滚动技术,只渲染用户可见的部分数据。这可以显著提高性能,因为页面上只会存在少量元素。
  **搜索和过滤:** 提供搜索和过滤功能,让用户可以根据需要筛选数据,以减少显示的数据量。
  **无限滚动:** 当用户滚动到页面底部时,自动加载更多数据。这种方式可以实现平滑的用户体验,同时避免一次性加载大量数据。
  **分批渲染:** 将数据分成多个批次,每次渲染一部分数据。可以使用定时器或异步渲染来逐步加载和显示数据。
  **懒加载:** 对于图片等资源,使用懒加载技术,只在元素进入可视区域时加载资源。
  **使用列表组件:** 使用列表组件,如Vue的`<v-for>`或React的`map`函数,来迭代渲染数据。这些组件通常具有内置的虚拟滚动和性能优化功能。
  **前端缓存:** 如果数据不经常变化,可以考虑在前端进行数据缓存,以减少对后端服务器的请求。
  **后端分页:** 如果可能的话,从后端请求数据时,使用分页查询来减少每个请求的数据量。
  **数据合并:** 如果数据中有大量重复的内容,可以在前端对数据进行合并和去重,以减小数据规模。
  **数据压缩:** 如果数据传输量大,可以考虑使用数据压缩技术来减小数据的大小。
  **性能优化工具:** 使用浏览器的性能分析工具来检测瓶颈并进行性能优化。

但是在实际的工作中基本是用封装好的组件,自己处理那么多数据还是第一次碰见,其实很混乱不知道如何写,百度和chatGPT大部分是分页,虚拟列表相对是比较多的处理方案。

由于本次维护的项目页面存在全选复选框,导致分页查接口的方法无法实现。公司的后端让我看调接口查10000条数据需要多长时间,我大概看了一下352ms左右,其实是可接受的范围,但是页面渲染那么多数据卡顿的一直转圈,于是任务落到前端的头上,我最开始想着虚拟列表和懒加载这两个方法,但是无从下手,而且任务也在催促当天要发版,于是就想着参照项目之前分页操作使用的scroll-view 可滚动视图区域进行手动分页。

scroll-view

<scroll-view
    :scroll-top="myScrollRightTop"
    scroll-y
    scroll-with-animation
    class="right-box"
    @scroll="myRightScroll"
    @scrolltolower="onScrollBottom"
    >
</scroll-view>

data

data:{
    foodList: [], //存储的数据
    displayedFoodData: [], // 显示的数据
    batchSize: 10, // 每次加载的数据数量
    currentIndex: 0, // 当前数据索引
}

method

    buildFoodList() {
      return new Promise((resolve, reject) => {
        this.foodList = []
        this.currentIndex = 0
        findAppletGoodsFoodList({
            pageNum: 1,
            pageSize: 1000,
          }).then(response => {
            if (response.errCode === 0) {
               // 存储数据
              this.foodList = this.$s.clone(response?.data || [])
               // 存储数据长度大于10时,截取十条数据显示,当前数据索引 + 1
              
              if(this.foodList.length > 10) {
                this.displayedFoodData = this.foodList.slice(0,10)
                console.log(this.displayedFoodData);
                this.currentIndex = 1
              } else {
                // 否则 将存储的数据直接赋值给显示数据
                this.displayedFoodData = this.foodList
              }
            } else {
              this.foodList = []
              this.$s.toast(response.message)
            }
          }).catch(error => {
            this.foodList = []
          }).finally(() => {
            resolve()
          })
      })
    },
    /**
     * @description scroll触底
     */
    onScrollBottom() {
       // 节流
      this.$s.throttle(() => {
          // 因为在获取foodList数据时,判断长度当前数据索引是1,所以当scroll触底时 (当前数据索引 + 1) X 10 判断是否大于10且小于foodList的长度
        if (this.batchSize < (this.currentIndex + 1) * this.batchSize <=  this.foodList.length) {
          // 当前数据索加1
          this.currentIndex++ 
          // 截取十个数据
          const temp = this.foodList.slice((this.currentIndex-1) * this.batchSize, this.currentIndex * this.batchSize) //
          // 将截取的数据存入到显示的数据内
          this.displayedFoodData.push(...temp)
          // (当前数据索引 + 1) X 10 判断是否大于foodList的长度
        } else if ((this.currentIndex + 1) * this.batchSize >  this.foodList.length) {
          // 显示数据的长度小于存储数据的长度,将不满十条数据的截取存入显示数据内
          if (this.displayedFoodData.length < this.foodList.length) {
            const temp = this.foodList.slice((this.currentIndex * this.batchSize, this.foodList.length-1))
            this.displayedFoodData.push(...temp)
          } else {
            this.$s.toast('没有更多了')
          }
        } else {
          this.$s.toast('没有更多了')
        }
      })
    },

onScrollBottom方法内处理显示数据的判断条件,当时写的时候感觉条件的判断是有问题的,但是任务比较急为了快点解决问题就没有优化。

到此为止是处理uniapp中要实现一次性加载10000条数据渲染问题。

菜鸟处理问题能力有限,应该有更好的方法实现一次性加载10000条数据渲染问题,希望各位大佬赐教。