Angular 15中如何获取路由跳转后含API调用的页面加载时间?
解决方案:全局跟踪API请求+资源加载完成状态
要实现所有API响应、脚本/图片等资源加载完成后触发函数,同时支持路由跳转场景,推荐采用「全局API请求拦截+Performance资源监控」的组合方案,无需逐个组件手动跟踪,具体实现如下:
核心思路
- 全局拦截所有API请求,维护一个活跃请求计数器,统计未完成的API数量
- 用
PerformanceObserver监听所有资源(脚本、图片、样式等)的加载状态,确认所有资源加载完毕 - 当「活跃API计数器归0」且「所有资源加载完成」时,触发目标函数;路由跳转时重置状态,重新监听
步骤1:封装API请求,跟踪活跃请求数
以Axios为例(Fetch可参考类似逻辑),在全局请求/响应拦截器中维护请求计数器:
// api/tracker.ts import axios from 'axios'; let activeApiRequests = 0; export const ApiTracker = { increment: () => activeApiRequests++, decrement: () => { activeApiRequests--; checkAllComplete(); }, reset: () => activeApiRequests = 0, getActiveCount: () => activeApiRequests }; // 创建全局Axios实例 export const apiClient = axios.create({ baseURL: '/api' }); // 请求拦截器:开始请求时增加计数器 apiClient.interceptors.request.use( (config) => { ApiTracker.increment(); return config; }, (error) => { ApiTracker.decrement(); return Promise.reject(error); } ); // 响应拦截器:请求结束(成功/失败)时减少计数器 apiClient.interceptors.response.use( (response) => { ApiTracker.decrement(); return response; }, (error) => { ApiTracker.decrement(); return Promise.reject(error); } );
步骤2:用PerformanceObserver监控资源加载
通过PerformanceObserver监听所有资源的加载状态,确认所有资源(脚本、图片、字体等)都已加载完成:
// resource/tracker.ts let allResourcesLoaded = false; export const ResourceTracker = { setLoaded: () => { allResourcesLoaded = true; checkAllComplete(); }, reset: () => allResourcesLoaded = false, isLoaded: () => allResourcesLoaded }; // 初始化资源监控 export function initResourceObserver() { const observer = new PerformanceObserver((entryList) => { // 过滤出未完成加载的资源条目 const incompleteResources = entryList.getEntries().filter(entry => entry.entryType === 'resource' && (entry.responseEnd === 0 || entry.loadingEnd === 0) ); // 没有未完成的资源时,标记为已加载 if (incompleteResources.length === 0) { ResourceTracker.setLoaded(); } }); // 监听所有资源类型的加载事件 observer.observe({ entryTypes: ['resource'] }); }
步骤3:合并状态,触发目标函数
编写全局检查逻辑,当API和资源都完成时触发指定函数:
// completion/checker.ts import { ApiTracker } from '../api/tracker'; import { ResourceTracker } from '../resource/tracker'; // 存储要触发的目标函数 let targetCallback: (loadTime: number) => void; export function setCompletionCallback(callback: (loadTime: number) => void) { targetCallback = callback; } export function checkAllComplete() { // 当活跃API为0且所有资源加载完成时触发 if (ApiTracker.getActiveCount() === 0 && ResourceTracker.isLoaded()) { // 获取当前时间戳(从页面初始化开始的耗时) const loadTime = performance.now(); targetCallback?.(loadTime); // 重置状态,避免重复触发(路由跳转时会重新初始化) ApiTracker.reset(); ResourceTracker.reset(); } }
步骤4:路由跳转时重置状态
以React Router为例,在路由切换时重新初始化监控,确保每次页面跳转都能正确统计:
// App.tsx import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; import { initResourceObserver } from './resource/tracker'; import { setCompletionCallback } from './completion/checker'; function App() { const location = useLocation(); useEffect(() => { // 路由切换时重置所有跟踪状态 initResourceObserver(); setCompletionCallback((loadTime) => { // 这里执行你的业务逻辑,比如上报加载时间、更新UI等 console.log('所有资源+API加载完成,总耗时:', loadTime.toFixed(2), 'ms'); }); }, [location.pathname]); return ( <div className="app"> {/* 你的路由内容 */} </div> ); } export default App;
边界情况处理
- 动态加载资源:
PerformanceObserver会自动监听后续动态加载的资源(比如懒加载图片、异步脚本),无需额外处理 - API请求失败:拦截器中已处理失败场景,确保计数器正确递减
- 重复触发:每次触发后自动重置状态,路由跳转时重新初始化,避免重复执行回调
内容的提问来源于stack exchange,提问作者Osama Naaz
相关产品推荐
相关产品推荐

