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


Posted in Javascript onMarch 30, 2017

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

$.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函数的功能可以看作是在指定时间之后启动一个新的线程来完成任务。

$.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时互相篡位。

通过这种方式执行, 页面瞬间就刷出来了,不用丝毫等待时间。 从同步改为异步,虽然代码的整体资源消耗增加了, 但是页面却能瞬间响应, 而且, 前端的运行环境是用户的电脑,因此些许的性能损失带来的用户体验提升相对来说还是值得的。

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

ps:setTimeout并不算真正的多线程, 但是为了方便表达,便借用了线程一词

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
javascript KeyDown、KeyPress和KeyUp事件的区别与联系
Dec 03 Javascript
类似GMAIL的Ajax信息反馈显示
Feb 16 Javascript
jQuery 类twitter的文本字数限制带提示效果插件
Apr 16 Javascript
兼容IE与firefox火狐的回车事件(js与jquery)
Oct 20 Javascript
说说JSON和JSONP 也许你会豁然开朗
Sep 02 Javascript
AngularJS在IE下取数据总是缓存问题的解决方法
Aug 05 Javascript
详解使用Vue.Js结合Jquery Ajax加载数据的两种方式
Jan 10 Javascript
jQuery插件Echarts实现的渐变色柱状图
Mar 23 jQuery
jQuery选择器特殊字符与属性空格问题
Aug 14 jQuery
vue webpack实用技巧总结
Apr 24 Javascript
解决bootstrap-select 动态加载数据不显示的问题
Aug 10 Javascript
jQuery实现放大镜案例
Oct 19 jQuery
ECMAScript6--解构
Mar 30 #Javascript
js图片放大镜效果实现方法详解
Oct 28 #Javascript
js a标签点击事件
Mar 30 #Javascript
JS+html5制作简单音乐播放器
Sep 13 #Javascript
TypeScript入门-接口
Mar 30 #Javascript
如何编写jquery插件
Mar 29 #jQuery
基于JavaScript实现瀑布流效果
Mar 29 #Javascript
You might like
东芝TOSHIBA RP-F11电路分析
2021/03/02 无线电
Yii框架中 find findAll 查找出制定的字段的方法对比
2014/09/10 PHP
Laravel实现用户注册和登录
2015/01/23 PHP
php通过asort()给关联数组按照值排序的方法
2015/03/18 PHP
php中删除、清空session的方式总结
2015/10/09 PHP
php与python实现的线程池多线程爬虫功能示例
2016/10/12 PHP
JavaScript实现为input与textarea自定义hover,focus效果的方法
2015/08/21 Javascript
日常收藏的jquery技巧
2015/12/02 Javascript
window.close(); 关闭浏览器窗口js代码的总结介绍
2016/07/14 Javascript
VueJS全面解析
2016/11/10 Javascript
AngularJS中指令的四种基本形式实例分析
2016/11/22 Javascript
D3.js中强制异步文件读取同步的几种方法
2017/02/06 Javascript
Vue.2.0.5过渡效果使用技巧
2017/03/16 Javascript
React diff算法的实现示例
2018/04/20 Javascript
jQuery利用FormData上传文件实现批量上传
2018/12/04 jQuery
[01:10]DOTA2 Supermajor:英雄,由我们见证
2018/05/14 DOTA
[46:59]完美世界DOTA2联赛PWL S2 GXR vs Ink 第二场 11.19
2020/11/20 DOTA
python益智游戏计算汉诺塔问题示例
2014/03/05 Python
python中实现精确的浮点数运算详解
2017/11/02 Python
Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容
2018/02/23 Python
python3+PyQt5实现自定义流体混合窗口部件
2018/04/24 Python
Python图像处理之图像的缩放、旋转与翻转实现方法示例
2019/01/04 Python
Python编写带选项的命令行程序方法
2019/08/13 Python
tensorflow中tf.slice和tf.gather切片函数的使用
2020/01/19 Python
Python GUI库PyQt5图形和特效样式QSS介绍
2020/02/25 Python
韩国邮政旗下生鲜食品网上超市:epost
2016/08/27 全球购物
事业单位个人应聘自荐信
2013/09/21 职场文书
医院反腐倡廉演讲稿
2014/09/16 职场文书
2014年学校领导班子对照检查材料
2014/09/19 职场文书
公司联欢会主持词
2015/07/04 职场文书
小学运动会加油稿
2015/07/22 职场文书
新年祝酒词大全
2015/08/11 职场文书
中考百日冲刺决心书
2015/09/22 职场文书
驾驶员安全责任协议书
2016/03/22 职场文书
python基础之文件处理知识总结
2021/05/23 Python
详解PHP服务器如何在有限的资源里最大提升并发能力
2021/05/25 PHP