用 setinterval 模拟进度条最直接,需控制数字从 0 增至 100 并绑定 dom;requestanimationframe 更流畅但需时间戳计算;xmlhttprequest 支持 onprogress 获取真实进度;abortcontroller 中断时须同步清理定时器或动画帧。

用 setInterval 模拟进度条最直接
没有真实后端接口时,前端常靠定时器“假装”加载中。核心是控制一个数字从 0 逐步增加到 100,再绑定到 DOM 元素的宽度或文本上。
关键点:别用 setTimeout 递归调用(易失控),setInterval 更可控;记得在达到 100 后 clearInterval,否则内存泄漏。
- 初始值设为
0,步长建议1~5,太小卡顿,太大不平滑 - 间隔时间选
50~200ms,100ms是较自然的节奏 - 避免在循环里频繁操作 DOM,先更新数据,再统一渲染
let progress = 0;
const timer = setInterval(() => {
progress += 2;
document.querySelector('.progress-bar').style.width = `${progress}%`;
if (progress >= 100) {
clearInterval(timer);
}
}, 100);
用 requestAnimationFrame 实现更流畅的动画
当对视觉平滑度有要求(比如上传大文件预览进度),requestAnimationFrame 比 setInterval 更合适——它会自动对齐屏幕刷新率,且页面切到后台时暂停,省资源。
但注意:它不保证固定时间间隔,只保证“下一帧”,所以不能直接当计时器用,需配合时间戳计算进度比例。
- 记录开始时间
startTime = performance.now() - 每次回调中算出已过毫秒数,除以总耗时得到
0~1的完成比 - 仍需手动判断是否结束并停止递归调用
const startTime = performance.now();
const duration = 3000; // 总时长 3s
<p>function animateProgress() {
const elapsed = performance.now() - startTime;
const progress = Math.min(100, (elapsed / duration) * 100);
document.querySelector('.progress-bar').style.width = <code>${progress}%</code>;
if (progress </p><h3>真实请求中如何把 <code>XMLHttpRequest</code> 的 <code>onprogress</code> 接出来</h3><p>只有原生 <code>XMLHttpRequest</code> 支持上传/下载进度事件,<code>fetch</code> 目前不支持(虽有提案,但未落地)。如果你用的是 <code>axios</code>,它底层封装了 <code>XMLHttpRequest</code>,可通过 <code>onUploadProgress</code> 或 <code>onDownloadProgress</code> 钩子拿到。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill3430" title="Alibabacloud Sdk Client Initialization For Java"><img
src="https://img.php.cn/upload/skill/000/000/081/178955835420587.jpg" alt="Alibabacloud Sdk Client Initialization For Java" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill3430" title="Alibabacloud Sdk Client Initialization For Java" class="overflowclass">Alibabacloud Sdk Client Initialization For Java</a>
<p class="overflowclass">在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。</p>
</div>
<a rel="nofollow" href="/xiazai/skill3430" title="Alibabacloud Sdk Client Initialization For Java" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><p>重点:必须设置 <code>Content-Length</code>(服务端要返回 <code>Content-Length</code> 响应头),否则 <code>event.total</code> 为 0,无法算百分比。</p>
-
event.loaded是已传输字节数,event.total是总字节数 - 上传时用
xhr.upload.onprogress,下载时用xhr.onprogress - 某些 CDN 或代理可能过滤掉
Content-Length,导致total === 0,此时只能显示“正在处理…”而非精确百分比
const xhr = new XMLHttpRequest();
xhr.open('POST', '/upload');
xhr.upload.onprogress = (event) => {
if (event.lengthComputable) {
const percent = (event.loaded / event.total) * 100;
document.querySelector('.progress-bar').style.width = `${Math.round(percent)}%`;
}
};
xhr.send(file);
用 AbortController 中断进度条逻辑
用户点了“取消”按钮后,不仅要终止请求,还要让进度条停在当前值或归零——否则会出现“请求已停,但进度条还在跑”的错觉。
常见误区:只调 abort(),却没清理定时器或动画帧。必须把所有异步控制句柄(intervalId、animationFrameId、controller)统一管理。
- 把
setInterval的返回值存到变量,abort时一起clearInterval - 用
requestAnimationFrame时,保存上次返回的 id,并在 abort 时用cancelAnimationFrame - 不要在
finally或catch里盲目重置进度为 0,得区分是成功结束、失败中断还是用户取消
进度条最难的不是怎么画,而是状态同步:请求、UI、用户操作三者之间稍有脱节,就会出现跳变、卡死或假完成。尤其在移动端弱网下,loaded 可能长时间不更新,这时候加个超时 fallback 比强行“动起来”更重要。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










