详细介绍浏览器中 performance 的 API

performance API介绍

在现代浏览器中,window.performance 提供了一系列 API 来测量和分析网页的性能。它主要用于跟踪页面加载时间、资源请求、用户交互延迟等。

在控制台上输入 window.performance 可以获取当前页面性能的一些信息。

window.performance输出结果

performance 属性

  • eventCounts: 返回当前全局对象中触发各个事件的数量。
  • memory: 基本内存使用情况(chrome扩展的非标准属性),目前已被废弃,暂时不确定未来是会被完全移除还是继续兼容,不推荐在项目中使用,可以使用 measureUserAgentSpecificMemory(),该方法目前还是实验性的,在使用的时候需要注意浏览器是否支持这个方法。
    • jsHeapSizeLimit: 内存大小限制。
    • totalJSHeapSize: 可使用的内存。
    • usedJSHeapSize: JS对象(包括V8引擎内部对象)占用的内存,不能大于 totalJSHeapSize,如果大于,有可能出现了内存泄漏。
  • navigation: 当前页面操作相关信息(页面的加载方式及重定向次数),目前已被废弃,暂时不确定未来是会被完全移除还是继续兼容,不推荐在项目中使用。
  • onresourcetimingbufferfull: 一个回调的 EventTarget,当浏览器的资源时间性能缓冲区已满时会触发
  • timeOrigin:性能测试开始时间戳(实验阶段)
  • timing: PerformanceTiming 实例,包含延迟相关的性能信息(目前已被废弃,但一些浏览器仍支持,尽量不要使用,使用 PerformanceNavigationTiming 替代)

我们来详细看看 eventCountstimingnavigationtimeOriginonresourcetimingbufferfull 这五个。

eventCounts(实验性质功能)

eventCounts浏览器的实验性 API,用于获取当前页面不同类型的事件触发次数。它可以帮助开发者分析用户交互行为,优化事件监听,减少不必要的事件绑定,提升性能。

它是一个 EventCounts 的实例,是 Map 类型,如果我们直接读取这个实例,并不能看到这个对象具体包含哪些数据,需要通过 entriesforEachget 这些方法才可以(可以查看 Map 中的实例方法)。

根据 规范,浏览器是支持 auxclick, click, contextmenu, dblclick, mousedown, mouseenter, mouseleave, mouseout, mouseover, mouseup, pointerover, pointerenter, pointerdown, pointerup, pointercancel, pointerout, pointerleave, gotpointercapture, lostpointercapture, touchstart, touchend, touchcancel, keydown, keypress, keyup, beforeinput, input, compositionstart, compositionupdate, compositionend, dragstart, dragend, dragenter, dragleave, dragover, drop 这 36 中事件的。

而我们通过 performance.eventCounts 获取到的触发事件的数量是当前浏览器支持的事件数量(不同浏览器有不同的实现,可能没有 36 种,本文的讲解是基于 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0 版本,该版本存在规范中的 36 种事件)。

我们试着读取一下 performance.eventCounts,看看里边是什么样的数据。

console.log(performance.eventCounts);

eventCounts

可以看到 eventCounts 中的保存的是 eventName: number 这样的数据,number 就是对应事件触发的次数。 浏览器默认会监听所有这些事件,哪怕我们没有手动添加 addEventListener 进行监听

我们可以通过这个属性将页面上的事件触发数量进行收集,发送给服务端进行数据分析。

注意:由于该属性是统计 window 中触发各个事件的数量,对于 spa 项目来说要特别小心,此时统计的并非是某个页面。

特性 说明
属性 performance.eventCounts
作用 统计不同类型事件的触发次数
数据类型 EventCounts对象(键值对存储事件类型和触发次数)
清除方式 无法手动清除,刷新页面会重置
兼容性 实验性 API,需要先检测支持情况
典型应用 性能优化、用户行为分析、调试

timing

虽然 timing 这个字段已经被废弃,但是为了兼容性,performance 中仍旧提供了这个字段,它的值是 PerformanceTiming 实例。

从输入 url 到用户可以使用页面的全过程时间统计,会返回一个 PerformanceTiming 实例对象,单位均为毫秒。

请添加图片描述

  • navigationStart 当前浏览器窗口的前一个网页关闭,发生 unload 事件时的时间戳。如果没有前一个网页,则它等于 fetchStart

  • unloadEventStart 如果前一个网页与当前网页同域,则为前一个网页的 unload 事件发生时的时间戳。如果没有前一个网页或之前网页跳转到不同域,则为 0

  • unloadEventEnd 如果前一个网页与当前网页同域,则为前一个网页的 unload 事件回调执行结束的时间戳。如果没有前一个网页或之前网页跳转不同域,则为0

  • redirectStart:第一次重定向开始时的时间戳,若无重定向或上次重定向不同源则为 0

  • redirectEnd: 最后一次重定向完成,即 HTTP 响应的最后一个字节返回时的时间戳,若无重定向或上次重定向不同源则为 0

  • fetchStart: 浏览器准备通过 HTTP 请求去获取页面的时间戳,这个时间是早于浏览器去检查对应缓存的时间。也就是浏览器会先发请求,然后记录这个时间,在判断浏览器中是否有缓存这个请求的响应,而不是先判断没有缓存后才发送请求。

  • domainLookupStart: 域名查询开始时间戳。若为持久连接,或从本地缓存获取则等同于 fetchStart

  • domainLookupEnd: 域名查询结束时的时间戳。若为持久连接,或从本地缓存获取则等同于 fetchStart

  • connectStart: 浏览器与服务器开始建立连接的时间戳,若为持久连接,则等同于 fetchStart

  • secureConnectionStart 浏览器与服务器开始安全链接握手的时间戳。若不要求安全连接则为0

  • connectEnd 浏览器与服务器连接建立完成的时间戳,即所有握手和认证过程全部完成,若为持久连接,则等同于 fetchStart

  • requestStart 浏览器向服务器发出 HTTP 请求文档(或开始读取本地缓存时)的时间戳

  • responseStart 浏览器从服务器收到(或从本地缓存读取)第一个字节时的时间戳

  • responseEnd 浏览器从服务器收到(或从本地缓存读取)最后一个字节时(若在此之前连接已经关闭,则返回关闭时)的时间戳

  • domLoadingDOM 解析器开始解析时的时间戳,即 document.readyState 属性变为 loading,且触发对应 readyStateChange 事件时

  • domInteractivehtml 解析器解析完成、开始加载子资源(如 css、图片等)的时间戳,即 document.readyState 属性变为 interactive,且触发对应 readyStateChange 事件时。

  • domContentLoadedEventStarthtml 解析器解析出来的全部脚本开始执行时的时间戳,即 documentDOMContentLoaded 事件被触发之前的时间。

  • domContentLoadedEventEnd:在所有需要尽快执行的脚本(无论是否按顺序执行)执行完毕之后的时间戳。

  • domComplete 当前 html 解析器在主线程完成所有任务时的时间戳,即 document.readyState 属性变为 complete,且触发对应 readyStateChange 事件时。

  • loadEventStart: 当前网页加载完成, windowload 事件回调函数开始执行的时间戳,若该事件还没发生就访问这个属性则返回为 0

  • loadEventEnd: 当前网页加载完成, windowload 事件回调函数结束时的时间戳,若该事件还没发生或者还没完成就访问这个属性则返回为 0

  • unloadEventStart:当页面跳转时开始执行 unload 事件的时间,如果没有上一级页面(通过地址栏直接跳转)或者是不同源、重定向等,都是 0

  • unloadEventEnd:当页面跳转时结束 unload 事件的时间,如果没有上一级页面(通过地址栏直接跳转)或者是不同源、重定向等,都是 0

timing 对象各个关键时间点的含义如下所示:

timing

根据 timing 对象提供的时间点,可以进行以下计算:

  • 重定向耗时: redirectEnd - redirectStart

  • DNS 查询耗时: domainLookupEnd - domainLookupStart

  • TCP 链接耗时: connectEnd - connectStart

  • SSL 安全连接耗时: connectEnd - secureConnectionStart

  • 网络请求耗时(TTFB): responseStart - requestStart

  • HTML 下载耗时: responseEnd - responseStart

  • 解析 dom 树耗时: domComplete - domInteractive

  • 资源加载耗时: loadEventStart - domContentLoadedEventEnd

  • 白屏时间: responseStart - fetchStart

  • domready 时间(用户可操作时间节点): domContentLoadedEventEnd - fetchStart

  • 页面完全加载时间: loadEventStart - fetchStart

封装以上几个方法:

function getPerformanceTiming() {
  const performance = window.performance;
  if(!performance) {
    console.log('该浏览器暂不支持performance');
    return;
  }
  const timing = performance.timing;
  return {
    redirectTime: timing.redirectEnd - timing.redirectStart,
    dnsTime: timing.domainLookupEnd - timing.domainLookupStart,
    tcpTime: timing.connectEnd - timing.connectStart,
    sslTime: timing.secureConnectionStart === 0 ? 0 : (timing.connectEnd - timing.secureConnectionStart),
    requestTime: timing.responseStart - timing.requestStart,
    htmlDownloadTime: timing.responseEnd - timing.responseStart,
    domParse: timing.domComplete - timing.domInteractive,
    resourceLoadTime: timing.loadEventStart - timing.domContentLoadedEventEnd,
    blankTime: timing.responseStart - timing.fetchStart,
    domReady: timing.domContentLoadedEventEnd - timing.fetchStart,
    total: timing.loadEventStart - timing.fetchStart
  }
}
getPerformanceTiming()

从兼容性及后续维护考虑,最好从 PerformanceNavigationTiming 的实例中读取相关数据。

该属性是一个对象,有两个属性值

  • redirectCount: 重定向次数(但是这个接口有同源策略限制,即仅能检测同源的重定向)
  • type: 操作类型
    • TYPE_NAVIGATE(0): 当前页面是通过点击链接,书签和表单提交,或者脚本操作,或者在url中直接输入地址
    • TYPE_RELOAD(1): 点击刷新页面按钮或者通过 Location.reload() 方法显示的页面
    • TYPE_BACK_FORWARD(2): 页面通过历史记录和前进后退访问时
    • TYPE_UNDEFINED(255): 任何未由上述值定义的导航类型

虽然与 window 对象中的 navigation 同名,但是它们指代的意义是完全不一样的。

目前已被废弃,暂时不确定未来是会被完全移除还是继续兼容,不推荐在项目中使用。但是可以使用 PerformanceNavigationTiming 来获取到相关信息。

timeOrigin

返回性能测量开始时的时间的高精度时间戳。其实就是文档/页面加载的时间点,即文档创建时的时间戳。这个时间点通常用于与其他性能测量(如资源加载时间)进行比较,帮助开发者分析页面加载过程的性能。

例如,如果我们在页面加载的某个时间点使用 performance.now(),这个值是相对于 performance.timeOrigin 的。如果我们想计算某个资源加载的时间,可以这样做:

const timeOrigin = performance.timeOrigin; // 文档的时间原点
const now = performance.now(); // 从页面加载开始经过的时间(毫秒)

console.log('文档时间原点:', timeOrigin);
console.log('从加载开始经过的时间:', now);

onresourcetimingbufferfull

onresourcetimingbufferfull 是一个事件处理器,专门用于处理浏览器中 resourcetimingbufferfull 事件。

resourcetimingbufferfull 事件用于指示浏览器的资源时间数据缓冲区已满。这意味着浏览器无法再记录新的资源性能数据,因为达到其容量限制。

当资源时间数据缓冲区满时,这个事件会被触发,允许开发者执行相应的操作。在这个事件触发后,浏览器将开始丢弃最旧的性能数据,以便为新的数据腾出空间。

performance.onresourcetimingbufferfull = function() {
    // 资源时间缓冲区已满,开始处理数据

    // 获取当前的资源性能数据
    const entries = performance.getEntriesByType('resource');

    // 处理这些数据,例如上传到服务器或进行分析
    console.log(entries);

    // 清理数据,以便后续处理(可选)
    performance.clearResourceTimings();
};

浏览器的资源时间缓冲区的大小并不是固定的,它取决于各个浏览器的实现和版本。一般来说,缓冲区的大小通常在几百到几千个资源条目之间。

performance 方法

getEntries

获取所有资源请求的时间数据。

这个函数返回一个按 startTime (开始时间)排序的对象数组,数组成员除了会自动根据所请求资源的变化而改变以外,还可以用 mark(), measure() 方法自定义添加。

获取的资源类型有非常多,可以通过 PerformanceObserver.supportedEntryTypes 这个属性来查看当前浏览器支持的资源类型:

PerformanceObserver.supportedEntryTypes

// ['element', 'event', 'first-input', 'largest-contentful-paint', 'layout-shift', 'long-animation-frame', 'longtask', 'mark', 'measure', 'navigation', 'paint', 'resource', 'visibility-state']

element(已被弃用)

注意,这里的弃用指的并不是浏览器不支持这些资源类型,而是 performance 对象的方法已经不返回这些类型的数据了,但是可以通过 PerformanceObserver 获取,后续弃用类型同理,之后不再赘述。

event(已被弃用)
first-input

PerformanceEventTiming 实例,用于获取关于用户 首次输入事件(如点击、按键等,只有第一次的事件才会被记录)的性能条目。这种数据通常用于分析用户体验,特别是响应用户交互的速度。

performance.getEntriesByType("first-input");

[{
  cancelable: true,
  duration: 8,
  entryType: "first-input",
  interactionId: 2775,
  name: "pointerdown",
  processingEnd: 26628.799999952316,
  processingStart: 26628.699999928474,
  startTime: 26627,
  target:  "span.icon.icon-chevron"
}]

largest-contentful-paint(已被弃用)
layout-shift(已被弃用)
long-animation-frame

PerformanceLongAnimationFrameTiming实例,用于获取长动画帧的性能条目。 长动画帧通常是指那些耗时超过 16.67 毫秒(即每秒 60 帧的理想值)的动画帧。这种信息对于监测动画性能和优化用户体验非常重要。

performance.getEntriesByType('long-animation-frame');

[{

  blockingDuration: 210,
  duration: 263,
  entryType: "long-animation-frame",
  firstUIEventTimestamp: 0,
  name: "long-animation-frame",
  renderStart: 4505.899999976158,
  scripts: [PerformanceScriptTiming],
  startTime: 4243.399999976158,
  styleAndLayoutStart: 4506
}]

longtask(已被弃用)
mark

PerformanceMark 实例,是通过 performance.mark() 方法自定义的测量数据。

performance.getEntriesByType('mark');

[{
  detail: null,
  duration: 0,
  entryType: "mark",
  name: "name1",
  startTime: 5904.100000023842
}]

measure

PerformanceMeasure实例,通过 performance.measure() 方法添加的自定义测量数据。

performance.getEntriesByType('measure');

[{
  detail: null,
  duration: -0.2999999523162842,
  entryType: "measure",
  name: "name1",
  startTime: 14720776.199999928
}]

PerformanceNavigationTiming 实例,可用于获取与页面导航相关的性能条目。这些条目提供有关页面加载过程的信息,包括各种导航事件的性能指标。

performance.getEntriesByType('navigation');

只获取最后一次导航条目:performance.getEntriesByType(‘navigation’) 通常只会返回当前页面的最后一次导航条目。

用途:

  • 性能分析: 通过分析导航条目,开发者可以了解页面加载的性能,包括重定向次数、DNS 查找时间、连接时间等。

  • 优化加载时间: 识别影响加载速度的因素,从而进行相应的优化。

paint

PerformancePaintTiming 实例,用于获取与页面绘制(paint)相关的性能条目。这些条目记录了页面的绘制事件,可以帮助开发者了解页面的渲染性能。

performance.getEntriesByType('paint');

[{
  duration: 0,
  entryType: "paint",
  // name 的值为first-paint'是首次绘制、'first-contentful-paint'是首次内容绘制。
  name: "first-contentful-paint",
  startTime: 4521.600000023842
}]

resource

PerformanceResourceTiming 实例,用于获取与资源加载相关的性能条目。这些条目包括所有通过网络请求加载的资源,例如图片、样式表、脚本等。通过这些条目,开发者可以分析资源的加载性能,识别潜在的瓶颈。

performance.getEntriesByType('resource');

resource 有以下几种类型:

发起对象 描述
一个元素 link/script/img/iframe/video/audio等 通过标签形式加载的资源,值是该节点名的小写形式
css 资源文件 css 通过css样式加载的资源,比如background的url方式加载资源
异步请求对象 xmlhttprequest/fetch 通过xhr加载的资源
PerformanceNavigationTiming 实例 navigation 当对象是PerformanceNavigationTiming时返回
visibility-state

VisibilityStateEntry 实例,用于获取与文档可见性状态相关的性能条目。它记录了文档可见性变化的时刻,并允许开发者分析页面在可见和不可见状态下的性能表现。

performance.getEntriesByType('visibility-state');

[{
  duration: 0,
  entryType: "visibility-state",
  name: "visible",   // 或者 hidden
  startTime: 0
}]

getEntriesByName(name,type[optional])getEntriesByType(type)

  • name: 想要筛选出的资源名
  • type: entryType 的值中一个

返回值仍是一个数组,这个数组相当于 getEntries() 方法经过所填参数筛选后的一个子集

clearResourceTimings()

该方法无参数无返回值,可以清楚目前所有 entryType"resource" 的数据,用于写单页应用的统计脚本非常有用。

setResourceTimingBufferSize

setResourceTimingBufferSize(maxSize):设置浏览器性能测量缓冲区中 可维持的 resource 类型 entry 对象的最大数量。

注意,这个方法在某些浏览器中可能有限制,并不是所有浏览器都支持对缓冲区大小的调整。

标记相关

  • mark: 使用 name 名称创建一个当前时间戳标记。
  • mesure: 使用 name 名称创建一个从 startMark 开始到 endMark 结束的测量
  • clearMarks: 清除标记
  • clearMeasures: 清除测量
markclearMarks

mark 用于在代码中插入自定义标记。这些标记可以用于测量特定代码段的执行时间,以便进行性能分析。

语法:

performance.mark(name);

// 在代码执行前添加标记
performance.mark('start');

// 执行一些代码
for (let i = 0; i < 1000000; i++) {
    // 模拟一些计算
}

// 在代码执行后添加标记
performance.mark('end');

clearMarks 语法有两种

performance.clearMarks();
performance.clearMarks(name);

当没有传递 name 参数时,删除所有的 mark,传递 name 则删除指定的 mark

measureclearMeasures

measure 用于测量两个标记(mark)之间的时间。这有助于开发者分析代码执行的性能,并优化关键路径的效率。

measure 语法

performance.measure(name, startMark, endMark);

performance.mark('start');
setTimeout(() => {
  performance.mark('end');
  performance.measure('time', 'start', 'end')
}, 2000)

clearMeasures 语法也有两种

performance.clearMeasures();
performance.clearMeasures(name);

当没有传递 name 参数时,删除所有的 measure,传递 name 则删除指定的 measure

now

performance.now() 是当前时间与 performance.timing.navigationStart 的时间差,以微秒(百万分之一秒)为单位的时间,与 Date.now() - performance.timing.navigationStart 的区别是不受系统程序执行阻塞的影响,因此更加精准。

toJSON

一个 JSON 格式转化器,返回 Performance 对象的 JSON 格式。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件举报,一经查实,本站将立刻删除。

文章由技术书栈整理,本文链接:https://study.disign.me/article/202509/18.chrome-performance-api.md

发布时间: 2025-02-27