前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • Vue

    • 从源码解读Vue生命周期
    • 组件的本质
    • 有状态组件的设计
    • 设计 VNode
    • 辅助创建 VNode 的 h 函数
    • 自定义渲染器和异步渲染
    • 渲染器之挂载
    • 渲染器的核心 Diff 算法
    • 渲染器之patch
    • 图解 Vue 响应式原理
    • 图解 Vue 异步更新
    • 剖析 Vue 内部运行机制
    • vue响应式原理模拟
    • vue状态管理之vuex
    • 理解Vue的设计思想及实现Vue
    • diff算法深入
    • vue router vuex原理分析
    • Vue3初探响应式原理.
    • vue2源码分析
    • vue组件化实践
  • React

  • Webpack

  • Node

  • Javascript

  • 综合

完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

前端性能之Performance|原理篇

文章学习导航
面试总览

30 秒速记

  • 核心判断:性能优化先建立用户指标与资源、主线程、渲染和网络证据,再定位最长关键路径
  • 原理主线:围绕 「一、回顾页面加载过程」、「二、performance」、「三、动画帧率FPS」 建立输入、状态变化与输出之间的因果关系
  • 文章范围:系统介绍了前端性能监控的核心API-Performance,详细讲解了页面加载的各个阶段、关键性能指标的获取方法及其在性能优化中的应用,帮助开发者全面理解和提升网页加载速度与用户体验。
  • 边界与代价:实验室分数不等于真实用户体验,平均值也会掩盖长尾;优化一项指标可能转移成本
  • 工程落地:用现场数据确定瓶颈、做最小改动、对照验证并持续监控回归

Performance API 可以从页面导航、资源加载和内存等维度采集性能数据,并结合 requestAnimationFrame 近似观察动画帧率。 performance.timing 用于拆分 DNS、连接、请求和 DOM 阶段,getEntries() 则适合定位具体的脚本、样式或图片耗时。帧率不能只看一次结果,且通过 requestAnimationFrame 计算的是近似值,会与真实渲染帧率存在误差。

这篇文章不要按 API 清单来背。先用上面的 Mind Map 建立全局结构,再通过交互 DEMO 观察正常路径和边界路径如何改变状态;阅读正文时重点核对每一步的输入、负责执行的参与者、产生的中间状态以及最终可观察结果。遇到版本敏感结论,要把“历史实现”“当前行为”和“工程兼容策略”分开说明;遇到性能或架构取舍,则用实际指标、失败现象和验证手段支撑判断。

版本校准: 原理文章中的代码代表特定实现与写作时间。应用到当前项目时,应先确认浏览器、框架或工具的主版本,再区分稳定的规范语义、可变化的内部实现和项目自身约束。

Performance是一个做前端性能监控离不开的API,最好在页面完全加载完成之后再使用,因为很多值必须在页面完全加载之后才能得到。最简单的办法是在window.onload事件中读取各种数据。

# 一、回顾页面加载过程

要学习这套API的使用,先简单介绍下前端的基础知识

# 1.1 页面加载

一个页面的请求到响应再到显示出来,需要经过下面一些重要过程,当我们在浏览器输入一个URL或者说点击一个URL开始,会出现如下流程

  • 页面准备
  • 重定向:在header定义了重定向才会有这个过程,如果没有重定向,不会产生这个过程。
  • app cache:会先检查这个域名是否有缓存,如果有缓存就不需要DNS解析域名。这里的app是值应用程序application,不指手机app。
  • DNS解析:把域名解析成IP,如果直接用ip地址访问,不产生这个过程。
  • TCP连接:http协议是经过TCP来传输的,所以产生一个http请求就会有TCP connect,但是依赖于长连接,不会产生这个过程。
  • request header:请求头信息。
  • request body:请求体信息,比如get请求是没有请求体信息的,所以没有这个过程,这就是为什么把头跟体分开写的原因。
  • response header:响应头信息。
  • response body:响应体信息。
  • 解析HTML结构
  • 加载外部脚本和样式表文件:正常来说JS、css都是外部加载的,当然有不正常的人啊,比如我。
  • 解析并执行脚本代码
  • 构建与解析HTML DOM树:这个过程可以去了解下DOM树是怎样的就明白啦。
  • 加载外部图片
  • 页面加载完成,显示出来啦

# 1.2 重定向分析

  • app cach
  • DNS解析
  • TCP连接
  • request header
  • 重定向
  • app cach
  • DNS解析
  • TCP连接
  • request header

# 二、performance

# 2.1 performance.timing

这个API能帮我们得到整个页面请求的时间,如下图,在Chrome的Console是可以直接运行的

先解释下这些时间都是代表什么

timing 对象里边的数据比较多,梳理如下几个关键性的节点

  • fetchStart:发起获取当前文档的时间点,我的理解是浏览器收到发起页面请求的时间点;
  • domainLookupStart:返回浏览器开始DNS查询的时间,如果此请求没有DNS查询过程,如长连接、资源cache、甚至是本地资源等,那么就返回fetchStart的值;
  • domainLookupEnd:返回浏览器结束DNS查询的时间,如果没有DNS查询过程,同上;
  • connectStart:浏览器向服务器请求文档,开始建立连接的时间,如果此连接是一个长连接,或者无需与服务器连接(命中缓存),则返回domainLookupEnd的值;
  • connectEnd:浏览器向服务器请求文档,建立连接成功的时间;
  • requestStart:开始请求文档的时间(注意没有requestEnd);
  • responseStart:浏览器开始接收第一个字节数据的时间,数据可能来自于服务器、缓存、或本地资源;
  • unloadEventStart:卸载上一个文档开始的时间;
  • unloadEventEnd:卸载上一个文档结束的时间;
  • domLoading:浏览器把document.readyState设置为“loading”的时间点,开始构建dom树的时间点;
  • responseEnd:浏览器接收最后一个字节数据的时间,或连接被关闭的时间;
  • domInteractive:浏览器把document.readyState设置为“interactive”的时间点,DOM树创建结束;
  • domContentLoadedEventStart:文档发生DOMContentLoaded事件的时间;
  • domContentLoadedEventEnd:文档的DOMContentLoaded事件结束的时间;
  • domComplete:浏览器把document.readyState设置为“complete”的时间点;
  • loadEventStart:文档触发load事件的时间;
  • loadEventEnd:文档出发load事件结束后的时间

再来一张图,表示各阶段的开始与结束对应的时间

从以上的分析,我们就可以得到一些时间的计算

  • 准备新页面耗时:fetchStart - navigationStart
  • 重定向时间:redirectEnd - redirectStart
  • App Cache时间:domainLookupStart - fetchStart
  • DNS解析时间:domainLookupEnd -domainLookupStart
  • TCP连接时间:connectEnd - connectStart
  • request时间:responseEnd - requestStart这个计算是代表请求响应加起来的时间
  • 请求完毕到DOM树加载:domInteractive -responseEnd
  • 构建与解析DOM树,加载资源时间:domCompleter -domInteractive
  • load时间:loadEventEnd - loadEventStart
  • 整个页面加载时间:loadEventEnd -navigationStart
  • 白屏时间:responseStart-navigationStart

# 2.2 performance.getEntries()

这个API能帮我们获得资源的请求时间,包括JS、CSS、图片等

如上图可以看到这个API请求返回的是一个数组,这个数组包括整个页面所有的资源加载,上图打开了一个其中一个资源,可以看到如下信息

  • entryType:类型为resource
  • name:资源的url
  • initiatorType:资源是link
  • 资源时间:duration的值,是responseEnd - startTime得到的

# 2.3 performance.memory

这个API主要是得到浏览器内存情况

  • jsHeapSizeLimit:内存大小限制
  • totalJSHeapSize:可使用的内容
  • userdJSHeapSize:已使用的内容

userdJSHeapSize表示所有被使用的JS堆栈内存,totalJSHeapSize可使用的JS堆栈内存,如果userdJSHeapSize的值大于totalJSHeapSize,就可能出现内存泄漏

# 三、动画帧率FPS

# 3.1 流畅动画的标准

FPS 表示的是每秒钟画面更新次数。我们平时所看到的连续画面都是由一幅幅静止画面组成的,每幅画面称为一帧,FPS 是描述“帧”变化速度的物理量

  • 理论上说,FPS 越高,动画会越流畅,目前大多数设备的屏幕刷新率为 60 次/秒,所以通常来讲 FPS 为 60 frame/s 时动画效果最好,也就是每帧的消耗时间为 16.67ms

不同帧率的体验

  • 帧率能够达到 50 ~ 60 FPS 的动画将会相当流畅,让人倍感舒适;
  • 帧率在 30 ~ 50 FPS 之间的动画,因各人敏感程度不同,舒适度因人而异;
  • 帧率在 30 FPS 以下的动画,让人感觉到明显的卡顿和不适感;
  • 帧率波动很大的动画,亦会使人感觉到卡顿

# 3.2 获取我们页面动画当前的 FPS 值

那么我们该如何准确的获取我们页面动画当前的 FPS 值呢?

# 3.2.1 方法一 借助 Chrome 开发者工具

Chrome 提供给开发者的功能十分强大,在开发者工具中,我们进行如下选择调出 FPS meter 选项:

通过这个按钮,可以开启页面实时 Frame Rate (帧率) 观测及页面 GPU 使用率

但是这个方法缺点太多了

  • 这个只能一次观测一到几个页面,而且需要人工实时观测
  • 数据只能是主观感受,并没有一个十分精确的数据不断上报或者被收集
  • 因此,我们需要更加智能的方法。

# 3.2.2 方法二 借助 Frame Timing API

Blink 内核早期架构

  • 以 Chrome 浏览器内核 Blink 渲染页面为例。对早期的 Chrome 浏览器而言,每个页面 Tab 对应一个独立的 renderer 进程,Renderer进程中包含了主线程和合成线程。早期 Chrome 内核架构

其中,主线程主要负责:

  • Javascript 的计算与执行
  • CSS 样式计算
  • Layout 计算
  • 将页面元素绘制成位图(paint),也就是光栅化(Raster)
  • 将位图给合成线程

合成线程则主要负责:

  • 将位图(GraphicsLayer 层)以纹理(texture)的形式上传给 GPU
  • 计算页面的可见部分和即将可见部分(滚动)
  • CSS 动画处理
  • 通知 GPU 绘制位图到屏幕上

其实知道了这两个线程之后,下一个概念是厘清 CSS 动画与 JS 动画的细微区别(当然它们都是 Web 动画)

JS 动画与 CSS 动画的细微区别

  • 对于 JS动画而言,它们运行时的帧率即是主线程和合成线程加起来消耗的时间。对于流畅动画而言,我们希望它们每一帧的耗时保持在 16.67ms 之内;
  • 而对于 CSS 动画而言,由于其流程不受主线程的影响,所以希望能得到合成线程的消耗的时间,而合成线程的绘制频率也反映了滚动和 CSS 动画的流程性。

上面主要想得出的一个结论是。如果我们能够知道主线程和合成线程每一帧消耗的时间,那么我们就能大致得出对应的 Web 动画的帧率。那么上面说到的 Frame Timing API 是否可以帮助我们拿到这个时间点呢

什么是 Frame Timing API ?

Frame Timing API 是 Web Performance Timing API 标准中的其中一位成员。Web Performance Timing API 是 W3C 推出的一套性能 API 标准,用于帮助开发者对网站各方面的性能进行精确的分析与控制,提升 Web 网站性能

它包含许多子类 API,完成不同的功能,大致如下

← 虚拟DOM(二)小程序开发实践 →

fe
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • Vue

    • 从源码解读Vue生命周期
    • 组件的本质
    • 有状态组件的设计
    • 设计 VNode
    • 辅助创建 VNode 的 h 函数
    • 自定义渲染器和异步渲染
    • 渲染器之挂载
    • 渲染器的核心 Diff 算法
    • 渲染器之patch
    • 图解 Vue 响应式原理
    • 图解 Vue 异步更新
    • 剖析 Vue 内部运行机制
    • vue响应式原理模拟
    • vue状态管理之vuex
    • 理解Vue的设计思想及实现Vue
    • diff算法深入
    • vue router vuex原理分析
    • Vue3初探响应式原理.
    • vue2源码分析
    • vue组件化实践
  • React

  • Webpack

  • Node

  • Javascript

  • 综合