JavaScript监听资源加载并计算百分比需自主定义统计范围与完成度算法:遍历img/link/script等关键资源,监听load/error事件按数量比例计算进度;配合CSS transform: scaleX()实现高性能动画,避免依赖document.readyState等非连续状态。

怎么用 JavaScript 监听资源加载并计算百分比
浏览器原生不提供「整个页面加载进度百分比」的实时接口,window.onload 和 DOMContentLoaded 都是终点事件,没法中间取值。真要显示动态百分比,必须自己定义「哪些资源算进去」+「怎么估算完成度」。
常见做法是:提前列出关键资源(如图片、CSS、JS 文件路径),用 fetch 或 XMLHttpRequest 主动加载并监听 progress 事件;或者监听 document.querySelectorAll('img, link[rel="stylesheet"], script') 的 load / error 状态,按数量比例算百分比。
- 只统计
<img>标签?适合图文为主的页面,简单但不准(忽略 CSS/JS 阻塞渲染) - 把所有
<link rel="stylesheet">和<script>加进队列?要注意async/defer脚本不会阻塞解析,别误判为「未加载」 - 用
PerformanceObserver捕获resource类型?能拿到真实下载耗时,但无法获取总大小,还是算不出精确百分比
CSS 动画实现进度条视觉反馈
有了数值,下一步是让 0% → 100% 变成可见动画。别用 JS 频繁改 width——会触发重排。推荐纯 CSS 方案:transform: scaleX() + transition。
.progress-bar {
height: 4px;
background: #e0e0e0;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: #4caf50;
width: 0;
transform-origin: left center;
transition: transform 300ms ease-out;
}
然后 JS 只需更新 transform: scaleX(0.65),浏览器用 GPU 加速,不卡顿。注意:别写 width: 65%,移动端缩放或字体变化时可能错位。
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 想加数字文本?用单独
<span class="progress-text">65%</span>,避免和动画元素耦合 - 需要「加载完后淡出」?加个
opacity过渡,但别在100%瞬间display: none,否则动画中断 - 进度条太细看不清?改
height同时调border-radius保持圆角,别用box-shadow模拟粗线(模糊性能差)
为什么 document.readyState 不能当进度依据
document.readyState 只有 "loading"、"interactive"、"complete" 三个状态,不是连续值。它反映的是 HTML 解析阶段,和资源下载无关——比如一个 5MB 的图片还在加载,readyState 可能早已变成 "complete"。
实测中,很多开发者误以为监听 readystatechange 就能做进度条,结果用户看到「100%」时图片还没显示,体验断裂。更糟的是,某些懒加载库或 Webpack 分包会动态插入 <script>,进一步让这个状态和真实资源完成脱钩。
-
document.readyState === "interactive"时,CSS 可能未生效,getComputedStyle拿不到正确值 - 服务端渲染(SSR)页面中,
readyState切换极快,进度条刚闪一下就跳到 100%,起不到提示作用 - 如果依赖它做逻辑分支(比如「到 80% 才初始化轮播图」),大概率出错——因为根本没 80% 这个节点
第三方库要不要用?axios 和 lazysizes 的边界在哪
不要为了进度条引入完整打包工具链。像 axios 的 onDownloadProgress 只对单个请求有效,没法汇总整个页面;lazysizes 专注图片懒加载,不提供全局进度接口。
真正轻量可控的做法是手写 20 行左右的资源监听器:遍历 document.images,给每个绑 onload/onerror,用 Map 记录完成数,再配合 requestIdleCallback 安全更新 UI。这样代码可读、可 debug、不污染全局。
- CDN 加载的字体(
@font-face)无法用常规方式监听,得用FontFaceSet.load()单独处理 - Webpack 构建的项目,如果用了
import('./module.js')动态导入,这些模块要显式加入进度队列,否则永远卡在 99% - Service Worker 缓存场景下,
fetch可能秒返回,但实际是走缓存——此时progress事件不触发,得 fallback 到计时器兜底


















