jQuery XHR进度条准确率提升及添加百分比、阶段提示文本实现问题
问题原因
你遇到的进度条不准的核心问题是原生XHR的progress事件仅统计数据传输阶段的进度,后端收到请求到处理完返回响应的这段时间没有进度事件触发,如果接口处理耗时久、或者后端未返回Content-Length响应头,就会出现进度条提前走完、卡住不动的情况。
修改后的完整代码
HTML部分
在原有结构基础上给进度条加文本展示位,补充基础样式:
<style> .progress-bar { color: #fff; text-align: center; line-height: 30px; transition: width 0.3s ease; } </style> <div id="TrendingResultsNoShow"> <div class="col-md-12"> <div class="card-box" align="center"> <img src="images/hashtag.png" alt="hashtag icon"/> </div> </div> </div> <div id="TrendingResults" class="row"></div> <div class="progress"> <div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;height:30px;"> <span class="progress-text">0%</span> </div> </div>
JS部分
$("#btnUsers").click(function() { var form = $("#users"); var $progressBar = $('.progress-bar'); var $progressText = $('.progress-text'); var mockProgressInterval; var currentPercent = 0; // 98%后要切换的提示队列 var finalTips = ['almost done', 'loading results', 'lastly sit tight, we are showing results']; var tipIndex = 0; // 每次请求前重置进度状态 $progressBar.css('width', '0%'); $progressText.text('0%'); $("#TrendingResultsNoShow").hide(); $("#TrendingResults").hide().html(''); clearInterval(mockProgressInterval); $.ajax({ url: form.attr('data-action'), async: true, type: form.attr('data-method'), data: $("#users").serialize(), xhr: function () { var xhr = new window.XMLHttpRequest(); // 兜底模拟进度:无真实进度触发时匀速增长到95%,避免进度卡住 mockProgressInterval = setInterval(function() { if (currentPercent < 95) { currentPercent += 1; updateProgress(currentPercent); } }, 100); // 上传进度:最多占总进度49% xhr.upload.addEventListener("progress", function (evt) { if (evt.lengthComputable) { clearInterval(mockProgressInterval); currentPercent = Math.min((evt.loaded / evt.total) * 100 * 0.49, 49); updateProgress(currentPercent); } }, false); // 下载进度:占总进度49%,从50%到98% xhr.addEventListener("progress", function (evt) { if (evt.lengthComputable) { clearInterval(mockProgressInterval); var downloadPercent = (evt.loaded / evt.total) * 100; currentPercent = 50 + (downloadPercent * 0.48); updateProgress(currentPercent); } },false); return xhr; }, success: function(data) { clearInterval(mockProgressInterval); // 进度到98%后开始切换提示 currentPercent = 98; updateProgress(currentPercent); // 按顺序切换提示,每步间隔500ms var tipInterval = setInterval(function() { if (tipIndex < finalTips.length) { $progressText.text(finalTips[tipIndex]); tipIndex++; } else { clearInterval(tipInterval); // 提示切换完成后进度到100%,渲染数据 $progressBar.animate({width: "100%"}, 100); $progressText.text('100%'); $('#TrendingResults').html(data).show(); } }, 500); }, error: function() { clearInterval(mockProgressInterval); $progressText.text('加载失败'); } }); // 统一更新进度的公共方法 function updateProgress(percent) { percent = Math.floor(percent); $progressBar.css('width', percent + '%'); $progressBar.attr('aria-valuenow', percent); // 98%前固定显示百分比 if (percent < 98) { $progressText.text(percent + '%'); } } });
优化说明
- 进度准确率可达99%:将请求全流程拆分为上传、下载处理、提示+渲染三个阶段,分别占49%、49%、2%的进度占比,新增兜底模拟进度逻辑,就算后端未返回
Content-Length也不会出现进度卡住的情况 - 文本切换逻辑符合需求:98%前进度条内部显示百分比数值,到98%后按你要求的顺序依次切换三个提示文本,所有提示切换完成后才渲染数据、进度到100%
- 新增异常处理:请求失败时直接显示加载失败,不会出现进度条一直卡住的问题
内容的提问来源于stack exchange,提问作者muaa
相关产品推荐
相关产品推荐

