NProgress 跟随页面加载的原理

发布时间:2026/8/25 10:22:23
NProgress 跟随页面加载的原理 文章目录核心真相NProgress 无法追踪真实加载进度NProgress 的核心机制两套“跟随”策略1. “涓滴”算法智能模拟进度2. 事件驱动绑定关键生命周期浏览器真正的加载事件NProgress 的模仿对象 关键事件详解1. DOMContentLoaded - 核心内容就绪2. load - 所有资源加载完成3. readystatechange - 更细粒度的状态追踪4. beforeunload/unload - 页面离开事件现代前端框架中的实现策略Vue Router 集成示例处理异步组件加载NProgress 的配置与优化什么是涓滴算法NProgress是前端开发中常见的一个进度条组件但你是否好奇过它为什么能跟随页面加载事实上它并不能真正追踪浏览器加载进度而是通过智能模拟和事件绑定创造这种“跟随”的假象。核心真相NProgress 无法追踪真实加载进度首先要明确一个关键事实NProgress 本身无法精确获取浏览器对页面或资源的真实加载进度百分比。现代浏览器确实提供了加载进度信息但出于安全和性能考虑这些信息对 JavaScript 是不可见或受限的。NProgress 采用的是一种更巧妙的设计哲学通过模拟进度增长并绑定到开发者控制的加载事件上从而创建流畅的视觉反馈。NProgress 的核心机制两套“跟随”策略1. “涓滴”算法智能模拟进度当调用NProgress.start()时会触发“涓滴”trickle算法// 简化的算法逻辑NProgress.tricklefunction(){returnNProgress.inc(0.1Math.random()*0.1);// 随机增量前进};// 进度永远不会自行达到100%// 必须由开发者显式调用NProgress.done()来完成这种设计模拟了真实世界加载的不确定性进度以随机、缓慢的方式前进给用户“正在加载”的心理暗示但永远不会自行完成避免了假完成或卡在 99%的尴尬。2. 事件驱动绑定关键生命周期NProgress 真正的“跟随”能力来自于开发者将其绑定到应用的关键事件上// 示例在路由系统中绑定router.beforeEach((to,from,next){NProgress.start();// 路由开始前启动进度条next();});router.afterEach((){NProgress.done();// 路由完成后结束进度条});// 示例在HTTP请求中绑定axios.interceptors.request.use((config){NProgress.start();returnconfig;});axios.interceptors.response.use((response){NProgress.done();returnresponse;},(error){NProgress.done();returnPromise.reject(error);});浏览器真正的加载事件NProgress 的模仿对象为了理解 NProgress 在模仿什么我们需要了解浏览器真实的加载事件。以下流程图展示了传统页面加载的关键事件触发顺序服务器浏览器用户服务器浏览器用户4. DOM解析开始par[并行加载]5. 所有资源加载完成6. 页面完全就绪1. 触发导航/重新加载2. 发送HTTP请求3. 返回HTML文档触发DOMContentLoaded加载CSS加载JavaScript加载图片等资源触发load事件触发readystatechange(complete) 关键事件详解1. DOMContentLoaded - 核心内容就绪document.addEventListener(DOMContentLoaded,function(){console.log(DOM已完全解析可以操作DOM元素);// 此时CSSOM可能尚未构建完成});触发时机HTML 文档完全被解析和加载DOM 树构建完成不等待样式表、图像和子框架的加载完成NProgress 对应在单页应用中这类似于路由组件解析完成2. load - 所有资源加载完成window.addEventListener(load,function(){console.log(页面所有资源图片、CSS等已加载完成);// 这是传统页面加载的完成时刻});触发时机页面及其所有依赖资源图片、CSS、JS 等完全加载NProgress 对应NProgress.done()应该在此事件或其等效时刻调用3. readystatechange - 更细粒度的状态追踪document.onreadystatechangefunction(){console.log(当前状态:,document.readyState);// 状态值// loading - 文档仍在加载// interactive - DOM已可交互但资源仍在加载// complete - 文档和资源全部加载完成};4. beforeunload/unload - 页面离开事件window.addEventListener(beforeunload,function(event){// 可以在这里启动进度条NProgress.start();});window.addEventListener(unload,function(){// 页面即将卸载});现代前端框架中的实现策略在 Vue、React 等单页应用SPA中NProgress 的实现方式与传统页面有所不同Vue Router 集成示例importNProgressfromnprogress;importnprogress/nprogress.css;constrouternewVueRouter({...});// 全局前置守卫router.beforeEach((to,from,next){if(from.name!null){// 不是首次加载NProgress.start();}next();});// 全局后置钩子router.afterEach((){NProgress.done();});// 处理异步组件加载Vue.mixin({beforeRouteEnter(to,from,next){next(vm{// 组件内部资源加载完成后vm.$once(hook:mounted,(){if(to.meta.needsProgress){NProgress.done();}});});}});处理异步组件加载// Vue异步组件constAsyncComponent()({component:import(./MyComponent.vue),loading:{render(h){NProgress.start();returnh(div,加载中...);}},error:ErrorComponent,delay:200,// 延迟显示加载状态timeout:3000// 超时时间});NProgress 的配置与优化为了获得更好的“跟随”效果可以调整 NProgress 的配置NProgress.configure({minimum:0.08,// 最小百分比trickleSpeed:200,// 涓滴速度showSpinner:false,// 是否显示旋转图标easing:ease,// 动画缓动函数speed:500,// 动画速度template:div classbar rolebar/div// 自定义模板});什么是涓滴算法涓滴算法 是NProgress用来模拟加载进度的心理学策略——通过缓慢、随机的小幅进度增长让用户感觉页面确实在“努力加载”即使它并不知道真实进度。想象一个沙漏你无法知道具体流了多少沙子但看到沙子流动就知道时间在流逝。涓滴算法就是这种“视觉安慰剂”。// 简化的涓滴逻辑functiontrickle(){// 每次增加一个很小的随机值constrandomIncrement0.1Math.random()*0.1;// 0.1-0.2之间的随机值progressrandomIncrement;// 关键永远不会自动达到100%if(progress0.95){// 卡在95%以下setTimeout(trickle,200);// 200ms后再次增长}}背后的心理学原理进度可见性人脑对不确定的等待容忍度很低可见的进度能显著降低焦虑假性进展即使不是真实进度运动本身就能提供安慰如同电梯的“关门”按钮期望管理缓慢增长设定了“这需要时间”的预期避免了突然卡住的挫折感 感谢阅读想了解更多 我的博客网站 | 记录思考分享干货 我的个人主页 | 关于我、开源项目