You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React路由间百分比预加载进度条实现方法咨询

嘿,这个需求我之前也琢磨过,不用现成包完全可以自己实现核心逻辑,我给你拆解成几个关键步骤,你跟着思路走就行:

核心实现思路拆解

一、先明确:document/window没有直接获取待下载总量的方法

浏览器本身没有提供直接拿到路由切换时要加载的所有资源总量的API,因为这些资源(比如路由对应的组件代码chunk)是webpack打包后的产物,所以我们得提前从打包环节拿到每个chunk的大小信息,这是实现百分比进度的前提。

二、第一步:获取路由对应Chunk的大小

React路由切换时的代码分割(比如用React.lazy)会把每个路由组件打包成单独的chunk,webpack在构建时会生成包含所有chunk大小的stats.json文件。你可以:

  • 构建后把这个stats.json引入项目,或者在webpack配置里通过DefinePlugin把chunk大小注入全局变量,比如:
    // webpack.config.js
    const { StatsWriterPlugin } = require('webpack-stats-plugin');
    // 先生成stats.json,再读取它把chunk大小注入全局
    new DefinePlugin({
      'window.__CHUNK_SIZES__': JSON.stringify(require('./stats.json').assetsByChunkName)
    })
    
    这样你就能通过window.__CHUNK_SIZES__['About']拿到对应路由组件chunk的大小了(这里的About是你用/* webpackChunkName: "About" */指定的chunk名)。

三、第二步:监听Chunk加载进度

有了总大小,接下来要追踪加载的实时进度,有两种常用方式:

方式1:手动用Fetch加载Chunk(替代React自动加载)

如果不想用React.lazy的默认加载逻辑,可以手动fetch chunk,这样能直接拿到ProgressEvent的loaded和total:

const loadRouteComponent = async (chunkName) => {
  // 先从全局变量拿到chunk的URL和大小
  const chunkUrl = `/static/js/${chunkName}.bundle.js`;
  const totalSize = window.__CHUNK_SIZES__[chunkName];

  const response = await fetch(chunkUrl);
  const reader = response.body.getReader();
  let loaded = 0;

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    loaded += value.length;
    // 计算百分比,传递给进度条状态
    const progress = Math.min(Math.round((loaded / totalSize) * 100), 100);
    updateProgressBar(progress);
  }

  // 加载完成后执行chunk代码,获取组件
  const module = await import(/* webpackChunkName: "[request]" */ `./routes/${chunkName}`);
  return module.default;
};

方式2:用PerformanceObserver监听资源加载

如果还是想用React.lazy,可以用浏览器的PerformanceObserver监听资源加载事件,过滤出当前路由的chunk:

const observer = new PerformanceObserver((list) => {
  const entries = list.getEntriesByType('resource');
  entries.forEach(entry => {
    // 判断当前资源是不是目标路由的chunk
    if (entry.name.includes(window.__CURRENT_ROUTE_CHUNK__)) {
      const progress = Math.round((entry.transferSize / entry.decodedBodySize) * 100);
      updateProgressBar(progress);
    }
  });
});
observer.observe({ entryTypes: ['resource'] });

注意:这里需要在路由跳转时记录当前要加载的chunk名(__CURRENT_ROUTE_CHUNK__),方便过滤。

四、第三步:React中管理进度条状态

  • 用React Context或者轻量状态管理工具(比如Zustand)维护进度百分比的全局状态,进度条组件订阅这个状态,实时更新UI。
  • 路由切换的完整流程:
    • 开始跳转:初始化进度为0%,显示进度条;
    • 加载中:实时更新进度;
    • 加载完成:把进度拉到100%,延迟几秒后隐藏进度条;
    • 加载失败:重置进度,显示错误提示(可选)。

五、边界情况处理

  • 缓存资源:如果chunk已经在浏览器缓存里,直接设置进度为100%,避免进度条闪一下;
  • 多Chunk加载:如果一个路由依赖多个chunk,要把所有chunk的总大小相加,再累加每个chunk的已加载量;
  • 进度条动画:可以用CSS过渡让进度条的变化更平滑,避免跳变。

内容的提问来源于stack exchange,提问作者R.Thompson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:06:14