JavaScript如何一次性展现几万条数据

 

网上看到一道面试题:“若是后台传给前端几万条数据,前端怎么渲染到页面上?”,如何回答? 因而办公室沸腾了, 同事们讨论开了, 你一言我一语说出本身的方案。 有的说直接循环遍历生成html插到页面上;有的说应该用分页来处理;还有的说这个面试官是个白痴, 哪有后台传几万条数据给前端这种状况的;我仔细思考了一下,先不论后端到底会不会白痴到传几万条数据给前端,假如真碰到这种状况,那么若是前端获取到数据之后, 直接将数据转换成html字符串,经过DOM操做插入到页面,势必致使页面运行出现卡顿, 为此我还特地写了一个 demo测试了一下, 代码以下javascript

复制代码

$.get("data.json", function (response) {    //response里大概有13万条数据    loadAll( response );
});function loadAll(response) {    var html = "";    for (var i = 0; i < response.length; i++) {        var item = response[i];
        html += "<li>title:" + item.title + " content:" + item.content + "</li>";
    }
    $("#content").html(html);
}

复制代码

data.json中大概有13万条数据左右, 经过ajax获取数据后以最简单粗暴的方法展现数据,在chrome浏览器下, 刷新页面到数据显示,我心中默数, 整个过程大概花掉5秒钟左右的时间, 卡顿很是明显。 我大体观察了一下代码的运行时间,发现循环生成字符串这过程其实并不算太耗时, 性能瓶颈是在将html字符串插入到文档中这个过程上, 也就是 $("#content").html(html); 这句代码的执行, 毕竟有13万个li元素要被挺入到文档里面, 页面渲染速度缓慢也在情理之中。

既然一次渲染13万条数据会形成页面加载速度缓慢,那么咱们能够不要一次性渲染这么多数据,而是分批次渲染, 好比一次10000条,分13次来完成, 这样或许会对页面的渲染速度有提高。 然而,若是这13次操做在同一个代码执行流程中运行,那彷佛不但没法解决糟糕的页面卡顿问题,反而会将代码复杂化。 相似的问题在其它语言最佳的解决方案是使用多线程,JavaScript虽然没有多线程,可是setTimeout和setInterval两个函数却能起到和多线程差很少的效果。 所以,要解决这个问题, 其中的setTimeout即可以大显身手。 setTimeout函数的功能能够看做是在指定时间以后启动一个新的线程来完成任务。html

复制代码

$.get("data.json", function (response) {    //response里大概有13万条数据    loadAll( response );
});function loadAll(response) {    //将13万条数据分组, 每组500条,一共260组
    var groups = group(response);    for (var i = 0; i < groups.length; i++) {        //闭包, 保持i值的正确性
        window.setTimeout(function () {            var group = groups[i];            var index = i + 1;            return function () {                //分批渲染                loadPart( group, index );
            }
        }(), 1);
    }
}//数据分组函数(每组500条)function group(data) {    var result = [];    var groupItem;    for (var i = 0; i < data.length; i++) {        if (i % 500 == 0) {
            groupItem != null && result.push(groupItem);
            groupItem = [];
        }
        groupItem.push(data[i]);
    }
    result.push(groupItem);    return result;
}var currIndex = 0;//加载某一批数据的函数function loadPart( group, index ) {    var html = "";    for (var i = 0; i < group.length; i++) {        var item = group[i];
        html += "<li>title:" + item.title + index + " content:" + item.content + index + "</li>";
    }    //保证顺序不错乱
    while (index - currIndex == 1) {
        $("#content").append(html);
        currIndex = index;
    }
}

复制代码

以上代码大体的执行流程是

1. 用ajax获取到须要处理的数据, 共13万条
2. 将数组分组,每组500条,一共260组
3. 循环这260组数据,分别处理每一组数据, 利用setTimeout函数开启一个新的执行线程(异步),防止主线程因渲染大量数据致使阻塞。

loadPart函数中有这段代码前端

while (index - currIndex == 1) {
    $("#content").append(html);
    currIndex = index;
}

是为了保证不一样的线程中最终插入html到文档中时顺序的一致性, 不至于同时执行的代码在插入html时互相篡位。

经过这种方式执行, 页面瞬间就刷出来了,不用丝毫等待时间。 从同步改成异步,虽然代码的总体资源消耗增长了, 可是页面却能瞬间响应, 并且, 前端的运行环境是用户的电脑,所以些许的性能损失带来的用户体验提高相对来讲仍是值得的。

虽然示例中提到的状况在现实环境中几乎不可能出现, 可是在咱们平时的工做中总会有一些似是而非的场景出现, 利用里面的处理思路, 或许对咱们解决问题会有必定的帮助。
java