Table大数据渲染—缓存处理(二)

@whizbz11 2018-12-21 15:45:18发表于 iuap-design/blog

Table大数据渲染—缓存处理(二)

在上一篇“Table大数据渲染—丝般顺滑”已经实现一个基础的Table大数据渲染,若想真正做到丝般顺滑,还需要一些缓存策略。
主要有两点需要处理,1、上篇有说需要根据回调的handleScroll参数scrollTop,动态计算currentIndex,那如果滚动到第9000条,那需要循环9000次,所以这是一个优化点,即记录上次currentIndex,减少循环次数。2、如果上次的currentIndex与这次计算的currendIndex不同,则会重新获取data数据,进行渲染。这个也是一个优化点增加loadBuffer.

  • 缓存currentIndex
    修改前的主要代码:
	let temp = scrollTop;
    //根据scroolTop动态计算当前索引位置
    while (temp > 0) {
       temp -= this.cachedRowHeight[index] || rowHeight
       if(temp > 0){
          index += 1
       }
    }

修改后的代码

	 let index = currentIndex;//记录下次当前位置
        let temp = currentIndex ?nextScrollTop - currentScrollTop:nextScrollTop;
        const viewHeight = parseInt(scroll.y);
        const isOrder = temp > 0 ?true:false;//true为向下滚动、false为向上滚动
        
        //根据scrollTop计算下次当前索引的位置
        if(isOrder){
            while (temp > 0) {
                temp -= this.cachedRowHeight[index] || rowHeight
                if(temp > 0){
                  index += 1
                  //保存当前index对应的scrollTop
                this.currentScrollTop += this.cachedRowHeight[index]|| rowHeight;
                }
              }
        }else{
            while(temp < 0){
                temp += this.cachedRowHeight[index] || rowHeight
                if(temp < 0){
                  index -= 1
                  this.currentScrollTop -= this.cachedRowHeight[index]|| rowHeight;
                }
            }
        }
  • 增加loadBuffer减少render次数
    Alt text
    例如:当前起始位置为startIndex为10,最后位置为endIndex20,按之前的做法起始位置startIndex变为11时,需要动态获取endIndex21,然后重现renderTable。增加了loadBuffer 5之后,会先判断startIndex,和endIndex直接的数据是否已经缓存,若已经缓存则不进行render,否则进行render。
    修改后的代码:
 //如果之前的索引和下一次的不一样则重置索引和滚动的位置
        if(currentIndex !== index){
            _this.currentIndex = index;
            _this.scrollTop = nextScrollTop;
            let rowsInView = 0 ; //可视区域显示多少行
            let rowsHeight = 0; //可视区域内容高度

            //如果可视区域中需要展示的数据已经在缓存中则不重现render。
            if(viewHeight){
               //有时滚动过快时this.cachedRowHeight[rowsInView + index]为undifined
                while(rowsHeight < viewHeight && this.cachedRowHeight[rowsInView + index] ){
                    rowsHeight += this.cachedRowHeight[rowsInView + index];
                    rowsInView++;
                } 
                // 如果rowsInView 小于 缓存的数据则重新render 
                // 向下滚动 下临界值超出缓存的endIndex则重新渲染
                if(rowsInView+index > endIndex - rowDiff && isOrder){
                
                    this.startIndex = index;
                    endIndex = this.startIndex  + loadCount
                    if(endIndex > data.length){
                        endIndex = data.length 
                    }
                    this.endIndex = endIndex;
                    this.setState({needRender: !needRender });
                }
                // 向上滚动,当前的index是否已经加载(currentIndex),若干上临界值小于startIndex则重新渲染
                if(!isOrder && index < startIndex + rowDiff){
                    startIndex = index - this.loadCount/2;
                    if(startIndex<0){
                        startIndex = 0;
                    }
                    this.startIndex = startIndex;
                    this.endIndex = this.startIndex  + loadCount
                    this.setState({needRender: !needRender });
                }
            }
        }

加了这两项缓存,整体滚动起来还不错,比较平滑了,具体代码可以参考这里