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 防止刷新,后退,关闭
Aug 07 Javascript
JQuery的read函数与js的onload不同方式实现
Mar 18 Javascript
如何使用jQuery来处理图片坏链具体实现步骤
May 02 Javascript
jquery对dom的操作常用方法整理
Jun 25 Javascript
解析JavaScript中的不可见数据类型
Dec 02 Javascript
document.forms[].submit()使用介绍
Feb 19 Javascript
Bootstrap学习笔记之环境配置(1)
Dec 07 Javascript
利用原生JS与jQuery实现数字线性变化的动画
Feb 24 Javascript
Vue.js进行查询操作的实例详解
Aug 25 Javascript
jQuery实现文字超过1行、2行或规定的行数时自动加省略号的方法
Mar 28 jQuery
Vue状态模式实现窗口停靠功能(灵动、自由, 管理后台Admin界面)
Mar 06 Javascript
部署vue+Springboot前后端分离项目的步骤实现
May 31 Javascript
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
用php过滤危险html代码的函数
2008/07/22 PHP
写一段简单的PHP建立文件夹代码
2015/01/06 PHP
让whoops帮我们告别ThinkPHP6的异常页面
2020/03/02 PHP
jquery列表拖动排列(由项目提取相当好用)
2014/06/17 Javascript
jquery插件splitScren实现页面分屏切换模板特效
2015/06/16 Javascript
JavaScript中style.left与offsetLeft的使用及区别详解
2016/06/08 Javascript
基于jQuery实现弹出可关闭遮罩提示框实例代码
2016/07/18 Javascript
微信小程序 基础组件与导航组件详细介绍
2017/02/21 Javascript
JavaScript对象引用与赋值实例详解
2017/03/15 Javascript
JS实现unicode和UTF-8之间的互相转换互转
2017/07/05 Javascript
深入研究jQuery图片懒加载 lazyload.js使用方法
2017/08/16 jQuery
详解组件库的webpack构建速度优化
2018/06/18 Javascript
在vue项目中,将juery设置为全局变量的方法
2018/09/25 Javascript
JavaScript实现的开关灯泡点击切换特效示例
2019/07/08 Javascript
JavaScript canvas仿代码流瀑布
2020/02/10 Javascript
jquery绑定事件 bind和on的用法与区别分析
2020/05/22 jQuery
vue实践---根据不同环境,自动转换请求的url地址操作
2020/09/21 Javascript
基于jQuery拖拽事件的封装
2020/11/29 jQuery
Python的爬虫包Beautiful Soup中用正则表达式来搜索
2016/01/20 Python
Python实现迭代时使用索引的方法示例
2018/06/05 Python
Python使用combinations实现排列组合的方法
2018/11/13 Python
Django--权限Permissions的例子
2019/08/28 Python
python 画函数曲线示例
2019/12/04 Python
Pycharm pyuic5实现将ui文件转为py文件,让UI界面成功显示
2020/04/08 Python
python相对企业语言优势在哪
2020/06/12 Python
面向新手解析python Beautiful Soup基本用法
2020/07/11 Python
浅析python字符串前加r、f、u、l 的区别
2021/01/24 Python
matplotlib之pyplot模块之标题(title()和suptitle())
2021/02/22 Python
HTML5 SEO优化的一些建议
2020/08/27 HTML / CSS
三字经教学反思
2014/04/26 职场文书
市场开发计划书
2014/05/07 职场文书
五四青年节优秀演讲稿范文
2014/05/28 职场文书
营销计划书
2015/01/17 职场文书
话题作文之生命的旋律
2019/12/17 职场文书
MySQL安装后默认自带数据库的作用详解
2021/04/27 MySQL
MySQL GRANT用户授权的实现
2021/06/18 MySQL