JavaScript一次性展示几万条数据的优化方案

作者:巡夜人时间:2026-10-22 01:57:15浏览:111

本文探讨前端一次性渲染数万条数据导致的页面卡顿问题。通过对比全量渲染与分批异步渲染,指出DOM操作是性能瓶颈。利用setTimeout将大批量数据分割为小批次,在异步队列中逐步插入DOM,从而避免主线程阻塞,实现页面即时响应。

大数据量渲染的性能问题分析

曾有同事分享一道面试题:当后端返回数万条数据时,前端应如何高效渲染?这一话题引发了热烈讨论,大家提出了多种方案,包括直接循环生成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元素插入文档,导致渲染缓慢。

基于setTimeout的分批异步渲染方案

既然一次性渲染13万条数据会导致加载缓慢,可以尝试分批渲染,例如每次处理10000条,分13次完成。然而,若这13次操作在同一执行流程中同步运行,不仅无法解决卡顿,反而会增加代码复杂度。在其他语言中,多线程是解决此类问题的最佳方案;虽然JavaScript没有真正的多线程,但setTimeout和setInterval能模拟类似效果。因此,利用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;
}

采用这种方式执行后,页面瞬间完成渲染,无需等待。虽然从同步改为异步增加了整体资源消耗,但页面响应变得即时。考虑到前端运行环境为用户电脑,这种轻微的性能损失换取用户体验的提升是值得的。

虽然示例中的极端情况在现实中罕见,但日常工作中常遇到类似场景。借鉴其中的处理思路,或许能为解决其他问题提供帮助。

注:setTimeout并非真正的多线程,此处借用线程一词以便表述

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

作者最新文章