如何为DataTables实现加载进度条?进度条直接跳至100%
大数据量DataTables实现进度条的解决方案
问题根源
你当前代码的核心问题有两个:
forEach不支持异步等待,所有循环迭代会被一次性触发,await setTimeout只会阻塞单个回调函数,不会阻止整个循环执行,导致所有数据添加和进度条更新几乎瞬间完成,视觉上直接跳转到100%。- 逐条调用
table.row.add()会频繁触发DataTables内部逻辑,5000条数据的场景下性能极低,也会让浏览器无暇更新进度条UI。
最优实现方案
核心优化点
- 使用异步for循环替代forEach,确保每一步操作完成后再执行下一步,保证进度条逐步更新。
- 分批加载数据,减少DataTables的DOM操作次数,提升性能的同时让进度条更新更平滑。
- 确保UI线程有时间重绘,避免进度条卡顿或跳变。
完整代码实现
HTML部分
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet"/> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script> <div id="progress-bar" class="progress-bar-striped"> <div style="width: 0%;"> <p>0%</p> </div> </div> <table id="data" class="table display table-stripped"> <thead> <tr> <th>ID</th> <th>Album ID</th> <th>Title</th> <th>URL Photo</th> </tr> </thead> <tbody></tbody> </table>
CSS部分
.progress-bar-striped { overflow: hidden; height: 20px; margin-bottom: 20px; background-color: #f5f5f5; border-radius: 4px; box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); } .progress-bar-striped>div { background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-size: 40px 40px; float: left; width: 0%; height: 100%; font-size: 12px; line-height: 20px; color: #000000; font-weight: bold; text-align: center; box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); animation: progress-bar-stripes 2s linear infinite; background-color: #288ade; } .progress-bar-striped p { margin: 0; } @keyframes progress-bar-stripes { 0% { background-position: 40px 0; } 100% { background-position: 0 0; } }
JavaScript部分
let handleProgressBar = (id, value, total) => { let percent = Math.round((value / total) * 10000) / 100; $(id + " > div").html(`${percent}%`); $(id + " > div").css('width', `${percent}%`); } // 初始化DataTables,禁用非必要功能提升加载性能 let table = $('#data').DataTable({ ordering: false, searching: false, paging: false }); // 每批加载的数据量,可根据性能调整 const BATCH_SIZE = 50; fetch('https://jsonplaceholder.typicode.com/photos') .then(res => res.json()) .then(async res => { const totalItems = res.length; let loadedItems = 0; // 分批循环处理数据 for (let i = 0; i < totalItems; i += BATCH_SIZE) { const batch = res.slice(i, i + BATCH_SIZE); // 一次性添加整批数据 batch.forEach(data => { table.row.add([ data.id, data.albumId, data.title, data.url ]); }); // 更新进度 loadedItems += batch.length; handleProgressBar('#progress-bar', loadedItems, totalItems); // 留时间给浏览器更新UI await new Promise(r => setTimeout(r, 10)); } // 加载完成后恢复DataTables功能并绘制表格 table.ordering(true).searching(true).draw(); });
额外说明
BATCH_SIZE可按需调整:值越大加载速度越快,进度条更新间隔越长;值越小进度条越平滑,总加载时长略久。- 初始化时禁用排序、搜索等功能,能大幅降低大数据量下的初始加载开销,全部数据加载完成后再启用。
await setTimeout的等待时间是为了让浏览器有足够时间重绘UI,避免进度条无法实时更新。
内容的提问来源于stack exchange,提问作者Jordy
相关产品推荐
相关产品推荐

