百万数据怎样在前端疾速流通显现?

本文同步自我的博客园:http://hustskyking.cnblogs.com

假如要在前端显现大批的数据,平常的战略就是分页。前端要显现百万数据,这个需求是很少见的,然则展现千条轻微复杂点的数据,这类需求照样比较罕见,只需内存够,javascript 肯定是吃得消的,盘算几千上万条数据,js 效力基础不在话下,然则 DOM 的衬着浏览器扛不住,CPU 轻微搓点的电脑必定会卡爆。

本文的战略是,显现三屏数据,其他的移除 DOM。

一、 战略

下面是我简朴勾勒的一个草图,我们把一串数据放到一个容器当中,这串数据的高度(Data List)肯定是比 Container 的高度要高许多的,假如我们一次性把数据都显现出来,浏览器须要消费大批的时刻来盘算每一个 data 的位置,而且顺次衬着出来,全部过程当中 JS 并没有消费太多的时刻,开支主如果 DOM 衬着。

                          /==============> Data List
        |     ....     | /
        +--------------+/
+=======|=====data=====|========+
|       +--------------+        |
|       |     data     |        |
|       +--------------+        |\
|       |     data     |        | \
|       +--------------+        |  \======> Container
+=======|=====data=====|========+    
        +--------------+
        |     ....     |        Created By Barret Lee

为了处理这个题目,我们让数据是显现一部份,这一部份是 Container 可视地区的内容,以及高低各一屏(一屏指的是 Container 高度所能包容的地区大小)的缓存内容。假如 Container 比较高,也但是只缓存半屏,缓存的原因是,在我们转动转动条的时刻,js 须要时刻来拼集字符串(或许建立 Node ),这个时刻浏览器还来不及衬着,所以会涌现暂时的空缺,这类体验是相称不好的。

二、Demo

demo 在 IE 7、8 有 bug,请读者本身修复吧~

代码:

<title>百万数据前端疾速流通显现</title>
<style type="text/css">
#box {position: relative; height: 300px; width: 200px; border:1px solid #CCC; overflow: auto}
#box div { position: absolute; height: 20px; width: 100%; left: 0; overflow: hidden; font: 16px/20px Courier;}
</style>

<div id="box"></div>

<script type="text/javascript">
var total = 1e5
  , len = total
  , height = 300
  , delta = 20
  , num = height / delta
  , data = [];

for(var i = 0; i < total; i++){
    data.push({content: "item-" + i});
}

var box = document.getElementById("box");
box.onscroll = function(){
    var sTop = box.scrollTop||0
      , first = parseInt(sTop / delta, 10)
      , start = Math.max(first - num, 0)
      , end = Math.min(first + num, len - 1)
      , i = 0;

    for(var s = start; s <= end; s++){
        var child = box.children[s];
        if(!box.contains(child) && s != len - 1){
            insert(s);
        }
    }

    while(child = box.children[i++]){
        var index = child.getAttribute("data-index");
        if((index > end || index < start) && index != len - 1){
            box.removeChild(child);
        }
    }

};

function insert(i){
    var div = document.createElement("div");
    div.setAttribute("data-index", i);
    div.style.top = delta * i + "px";
    div.appendChild(document.createTextNode(data[i].content));
    box.appendChild(div);
}

box.onscroll();
insert(len - 1);
</script>

能够戳这个 demo,或许看这里 https://gist.github.com/barretlee/9744160

三、算法申明

1. 盘算 start 和 end 节点

        |              |
+=======|==============|========+——
|    ↓——+--------------+        | ↑
| delta |              |        |
|    ↑——+--------------+        | height
|       |              |        |
|       +--------------+        | ↓
+=======|==============|========+——  
        |              |

Container 能够包容的 Data 数量为 num = height / delta,Container 顶部第一个节点的索引值为

 var first = parseInt(Container.scrollTop / delta);

因为我们高低都有留出一屏,所以

var start = Math.max(first - num, 0);
var end = Math.min(first + num, len - 1);

2. 插进去节点

经由过程上面的盘算,从 start 到 end 将节点一次插进去到 Container 中,而且将末了一个节点插进去到 DOM 中。

// 插进去末了一个节点
insert(len - 1);
// 插进去从 start 到 end 之间的节点
for(var s = start; s <= end; s++){
    var child = Container.children[s];
    // 假如 Container 中已经有该节点,或许该节点为末了一个节点则跳过
    if(!Container.contains(child) && s != len - 1){
        insert(s);
    }
}

这里诠释下为什么要插进去末了一个节点,插进去节点的体式格局是:

function insert(i){
    var div = document.createElement("div");
    div.setAttribute("data-index", i);
    div.style.top = delta * i + "px";
    div.appendChild(document.createTextNode(data[i].content));
    Container.appendChild(div);
}

能够看到我们给插进去的节点都加了一个 top 属性,末了一个节点的 top 是最大的,只要把这个节点插进去到 DOM 中,才能让转动条拉长,让人觉得放了许多的数据。

3. 删除节点

为了削减浏览器的重排(reflow),我们能够隐蔽三屏以外的数据。我这里为了轻易,直接给删除掉了,后续须要再从新插进去。

while(child = Container.children[i++]){
    var index = child.getAttribute("data-index");
    // 这里记得不要把末了一个节点给删除掉了
    if((index > end || index < start) && index != len - 1){
        Container.removeChild(child);
    }
}

当 DOM 加载终了以后,触发一次 Container.onscroll(),然后全部顺序就 OK 了。

四、小结

本文主如果叙说大数据加载的一点基本原理,顺序可能有 bug,也有许多处所能够优化,了解下算法就好了。

    原文作者:小胡子哥
    原文地址: https://segmentfault.com/a/1190000000445290
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞