告别弃用API!手把手教你用performance.getEntriesByType检测页面刷新与跳转
最近在重构一个老项目时,我遇到了一个棘手的问题:原本用来判断页面是刷新还是首次加载的performance.navigation.type在Chrome控制台里赫然标着"Deprecated"(已弃用)。这让我意识到,很多前端开发者可能还在使用这个即将被淘汰的API,而新的替代方案PerformanceNavigationTiming虽然功能更强大,但相关资料却比较零散。
如果你也在为如何准确判断用户是通过刷新、前进后退还是正常导航进入页面而烦恼,这篇文章就是为你准备的。我会带你从零开始,深入理解这个API的演变历程,并给出实际可用的代码方案。
1. 为什么我们需要关注页面导航类型?
在开始技术细节之前,先聊聊为什么这个看似简单的功能如此重要。在我负责的一个电商项目中,我们需要根据用户进入页面的方式采取不同的策略:
- 首次加载:需要完整加载所有资源,初始化应用状态
- 页面刷新:可能需要重新获取某些动态数据,但可以复用部分缓存
- 前进/后退:可以利用浏览器缓存,甚至恢复之前的滚动位置和表单状态
以前我们依赖performance.navigation.type来做这些判断,但随着浏览器标准的演进,这个API已经被标记为弃用。更糟糕的是,不同浏览器的实现细节存在差异,导致我们的判断逻辑在某些边缘情况下失效。
1.1 传统方法的局限性
让我先展示一下我们之前使用的代码,这也是很多项目中常见的写法:
// 已弃用的传统写法
function detectNavigationTypeOld() {
const nav = window.performance.navigation;
switch(nav.type) {
case 0: // TYPE_NAVIGATE
console.log('正常导航(点击链接、输入URL等)');
return 'navigate';
case 1: // TYPE_RELOAD
console.log('页面刷新');
return 'reload';
case 2: // TYPE_BACK_FORWARD
console.log('前进/后退');
return 'back_forward';
default:
console.log('未知导航类型');
return 'unknown';
}
}
这段代码的问题在于:
- API已弃用:现代浏览器中会收到警告
- 类型值硬编码:0、1、2这些魔法数字让代码难以维护
- 信息有限:只能获取基本导航类型,缺少详细的性能数据
1.2 新API的优势
相比之下,新的PerformanceNavigationTiming API提供了更丰富的信息:
| 特性 | 旧API (performance.navigation) | 新API (PerformanceNavigationTiming) |
|---|---|---|
| 导航类型 | 仅type属性 | 详细的type字符串值 |
| 时间信息 | 无 | 完整的导航时间线数据 |
| 重定向信息 | redirectCount | 详细的redirectStart/End时间 |
| 资源大小 | 无 | encodedBodySize, decodedBodySize等 |
| 协议信息 | 无 | nextHopProtocol |
| 兼容性 | 已弃用 | 现代浏览器广泛支持 |
2. 深入理解PerformanceNavigationTiming
2.1 获取导航信息的新方法
让我们先看看如何获取新的导航信息。与直接访问performance.navigation不同,新API需要通过getEntriesByType方法:
// 获取导航性能条目的推荐方法
function getNavigationTiming() {
// 方法1:使用getEntriesByType
const navEntries = performance.getEntriesByType('navigation');
if (navEntries.length > 0) {
const navTiming = navEntries[0];
console.log('导航类型:', navTiming.type);
console.log('完整导航对象:', navTiming);
return navTiming;
}
// 方法2:使用PerformanceObserver(更推荐)
return null;
}
这里有个重要的细节:getEntriesByType('navigation')返回的是一个数组,即使通常只有一个导航条目。这是因为理论上一个页面可能有多个导航(比如iframe),但实践中我们通常取第一个。
2.2 导航类型的详细解读
新的type属性返回的是字符串,而不是数字,这让代码更加清晰:
// 新的导航类型判断
function detectNavigationType() {
const navEntries = performance.getEntriesByType('navigation');
if (navEntries.length === 0) {
console.warn('未找到导航性能条目');
return 'unknown';
}
const navTiming = navEntries[0];
switch(navTiming.type) {
case 'navigate':
console.log('正常导航:用户通过点击链接、输入URL、提交表单等方式进入');
break;
case 'reload':
console.log('页面刷新:通过刷新按钮、F5、location.reload()等方式');
break;
case 'back_forward':
console.log('前进/后退:通过浏览器历史记录导航');
break;
case 'prerender':
console.log('预渲染:页面在后台预加载');
break;
default:
console.log('未知导航类型:', navTiming.type);
}
return navTiming.type;
}
注意:
prerender类型在某些浏览器中可能不会出现,或者需要特定的配置才能触发。在实际使用中,我们主要关注前三种类型。
2.3 完整的导航时间线
PerformanceNavigationTiming最强大的功能之一是提供了完整的导航时间线。我们可以通过这些时间点计算各种性能指标:
// 计算关键性能指标
function calculatePerformanceMetrics() {
const navEntries = performance.getEntriesByType('navigation');
if (navEntries.length === 0) return null;
const timing = navEntries[0];
const metrics = {
// 导航类型
navigationType: timing.type,
// DNS查询时间
dnsLookupTime: timing.domainLookupEnd - timing.domainLookupStart,
// TCP连接时间
tcpConnectTime: timing.connectEnd - timing.connectStart,
// SSL握手时间(仅HTTPS)
sslHandshakeTime: timing.secureConnectionStart > 0
? timing.connectEnd - timing.secureConnectionStart
: 0,
// 请求响应时间(TTFB)
timeToFirstByte: timing.responseStart - timing.requestStart,
// 内容下载时间
contentDownloadTime: timing.responseEnd - timing.responseStart,
// DOM解析时间
domParseTime: timing.domComplete - timi


1351

被折叠的 条评论
为什么被折叠?



