Web 性能是 Web 开发的一个重要方面,侧重于网页加载速度以及对用户输入的响应速度 通过优化网站来改善性能,可以在为用户提供更好的体验 网页性能既广泛又非常深入 1. 为什么性能这么重要? 1. 性能关乎留住用户 性能对于任何在线业务都至关重要 与加载速度缓慢、让人感觉运行缓慢的网站相比,加载速
Web
性能是
Web
开发的一个重要方面,侧重于网页加载速度以及对用户输入的响应速度
通过优化网站来改善性能,可以在为用户提供更好的体验
网页性能既广泛又非常深入
性能对于任何在线业务都至关重要
与加载速度缓慢、让人感觉运行缓慢的网站相比,加载速度快并能及时响应用户输入的网站能更好地吸引并留住用户
性能会对网站用户是否会浏览应用产生重大影响
随着网页开始加载,用户会等待一段时间,等待内容显示。在此之前,就谈不上用户体验
快速连接会让这种体验一闪而过。而如果连接速度较慢,用户就不得不等待
性能是打造良好用户体验的基本要素
当网站发送大量代码时,浏览器必须使用用户流量套餐中的兆字节流量下载应用
尤其是移动设备的
CPU
性能和内存有限。这可能会导致糟糕的性能条件,而且考虑到人们了解人类的行为,用户只能容忍网站上的不利条件长达很长的时间,然后才会放弃网站
感知加载速度:网页可以多快地加载网页中的所有视觉元素并将其渲染到屏幕上
加载响应速度:页面加载和执行组件快速响应用户互动所需的任何
JavaScript
代码的速度
运行时响应速度:网页在加载后对用户互动的响应速度
视觉稳定性:页面上的元素是否会以用户意想不到的方式发生偏移,是否可能会干扰用户的互动?
流畅性:过渡和动画是否以一致的帧速率渲染,并在一种状态之间流畅地流动?
FCP(First Contentful Paint)
:从网页开始加载到网页内容的任何部分呈现在屏幕上所用的时间
LCP(Largest Contentful Paint)
:从网页开始加载到屏幕上呈现最大的文本块或图片元素所用的时间
INP(Interaction to Next Paint)
:与网页进行的每次
tap
、
click
或键盘互动的延迟时间,并根据交互的数量选择页面中最差的交互延迟作为单个代表性值来描述页面的总体响应性
TBT(Total Blocking Time)
:从
FCP
到可交互时间 (
TTI
) 之间的总时长
CLS(Cumulative Layout Shift)
:从页面开始加载到其生命周期状态更改为隐藏期间发生的所有意外布局偏移的累计分数
TTFB(Time to First Byte)
:网络使用资源的第一个字节响应用户请求所花费的时间
FID(First Input Delay)
:用户首次与网页互动(即,点击链接、点按按钮或使用由
JavaScript
提供支持的自定义控件)到浏览器实际能够开始处理事件处理脚本以响应相应互动的时间
Web
页面性能衡量指标-以用户为中心的性能指标
每个网站都是从请求
HTML
文档开始的,该请求对网站的加载速度有着重大影响
要想构建可快速加载的网站,第一步就是要及时从服务器接收网页
HTML
的响应
当在浏览器的地址栏中输入网址时,浏览器会向服务器发送
GET
请求进行检索
网页的第一个请求针对的是
HTML
资源,因此,确保
HTML
以最短延迟快速到达是关键性能目标
在请求资源时,服务器可能会做出一个重定向响应,该重定向可以是永久重定向(301
Moved Permanently
响应)或临时重定向(302
Found
响应)
重定向会降低网页加载速度,因为它需要浏览器在新位置发出额外的
HTTP
请求来检索资源。重定向有两种类型:
Web
服务器上
缓存
HTML
响应很困难,因为响应可能包含指向其他关键资源(例如
CSS
、
JavaScript
、图片和其他资源类型)的链接。这些资源的文件名中可能包含唯一指纹,该指纹会根据文件的内容而变化
但是较短的缓存生命周期(而不是不缓存)具有诸多优势:
允许在
CDN
中缓存资源,减少从源服务器传送的请求数量
在浏览器中传送资源,从而重新验证资源而不是再次下载此
可以将缓存资源的适当时间设置为合适的分钟数
缓存
HTML
的一种方法是使用
ETag
或
Last-Modified
响应标头
ETag
(也称为实体标记)标头是一个标识符,用于唯一标识所请求资源,通常使用资源内容的哈希值:
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
每当资源发生变化时,都必须生成新的
ETag
值。在后续请求中,浏览器会通过
If-None-Match
请求标头发送
ETag
值。如果服务器上的
ETag
与浏览器发送的
ETag
匹配,服务器会返回
304 Not Modified
响应,浏览器则会使用缓存中的资源。虽然这仍然会导致网络延迟,但
304 Not Modified
响应比整个
HTML
资源小得多
但是,重新验证资源的新鲜度涉及的网络延迟也本身也是一个缺点,需自行决定以这种方式缓存
HTML
的额外工作是否值得,或者最好是谨慎操作,不必费心缓存
HTML
内容。
如果响应未缓存,则服务器的响应时间在很大程度上取决于的托管服务提供商和后端应用堆栈
与动态网页相比,提供动态生成的响应(例如从数据库获取数据)的网页的
TTFB
可能更高,无需在后端投入大量计算时间即可立即提供
基于文本的响应(例如
HTML
、
JavaScript
、
CSS
和
SVG
图片)应进行压缩,以减小通过网络传输时的大小,从而加快其下载速度。最常用的压缩算法是
gzip
和
Brotli
。
Brotli
比
gzip
提高了约 15% 到 20%。
Brotli
,所有主流浏览器都支持
Brotli
,但如果网站有大量用户在旧版浏览器中使用,请确保将
gzip
用作后备选项,因为任何压缩都比不进行压缩要好。
KiB
)压缩得不太好,有时甚至根本压缩不到。任何类型的数据压缩的效果都取决于能够使用压缩算法找到更多可压缩数据位的大量数据。文件越大,压缩效果就越好
JavaScript
、
CSS
和
SVG
图片等静态资源应静态压缩,而
HTML
资源应动态压缩。
CDN
是分布式服务器网络,服务器从源服务器缓存资源,反过来再从物理上更靠近用户的边缘服务器传送资源。在距离用户较近时,可以缩短往返时间 (
RTT
),而
HTTP/2
或
HTTP/3
、缓存和压缩等优化技术则可以让
CDN
更快地提供内容,而不是从源服务器提取内容。在某些情况下,使用
CDN
可以显著改善网站的
TTFB
。
关键渲染路径是网页性能中的一个概念。
关键渲染路径是指网页开始在浏览器中呈现之前所涉及的步骤。为了呈现网页,浏览器需要
HTML
文档本身以及呈现该文档所需的所有关键资源。
网络是自然分布的。与客户端和 APP 不同,浏览器不能依赖于拥有呈现页面所需的所有资源的网站。因此,浏览器非常擅长渐进式呈现页面。原生应用通常有一个安装阶段,然后是运行阶段。然而,对于网页和网络应用来说,这两个阶段之间的界限就不那么明显了。
浏览器需要知道它应该等待的最小资源数量,以避免呈现明显不正常的体验。
另一方面,浏览器也不应该等待超过必要的时间才向用户显示一些内容。浏览器在执行初始呈现之前所采取的步骤序列称为关键渲染路径。
呈现路径涉及以下步骤:
通过
HTML
构建文档对象模型 (
DOM
)
通过
CSS
构建
CSS
对象模型 (
CSSOM
)
应用任何会更改
DOM
或
CSSOM
的
JavaScript
通过
DOM
和
CSSOM
构建渲染树
在页面上执行样式和布局操作,看看哪些元素适合显示
在内存中绘制元素的像素
如果有任何像素重叠,则合成像素
以物理方式将所有生成的像素绘制到屏幕上
只有在完成所有这些步骤后,用户才会在屏幕上看到内容
这一呈现过程会发生多次。初始渲染会调用此流程,但随着更多会影响网页渲染的资源可用,浏览器将会重新运行此流程(或许只是其中的一部分),以更新用户看到的内容。关键渲染路径侧重于之前为初始渲染概述的流程,并依赖于执行初始渲染所需的关键资源
浏览器需要等待一些关键资源下载完毕,然后才能完成初始渲染。这些资源包括:
HTML
的一部分
元素中阻塞渲染的
CSS
元素中的阻塞渲染的
JavaScript
关键在于浏览器以流式方式处理
HTML
。浏览器一旦获取网页
HTML
的任何部分,就会开始对其进行处理。然后,浏览器就可以(并且通常确实)决定先呈现网页,然后再接收网页的其余部分
HTML
网页加载时,其
HTML
中会引用许多资源,通过
CSS
提供网页的外观和布局,并通过
JavaScript
提供互动性。
CSS
是一种阻塞渲染的资源,因为它会阻止浏览器渲染任何内容,直至构建了
CSS
对象模型 (
CSSOM
)。浏览器会阻止呈现,以防止出现非样式内容闪烁 (
FOUC
)
渲染阻塞未必是不可取的,但需要通过对
CSS
进行优化来最大限度地缩短其持续时间
预加载扫描程序的角色是推测性,也就是说,它会检查原始标记,以便查找资源,以便在主要
HTML
解析器发现之前抓取相应资源
预加载扫描程序是一种浏览器优化,采用辅助
HTML
解析器的形式,可扫描原始
HTML
响应,以找出并推测性地提取资源,然后主
HTML
解析器才会发现这些资源
为了充分利用预加载扫描器,服务器发送的
HTML
标记中应包含关键资源。预加载扫描器无法发现以下资源加载模式:
CSS
使用
background-image
属性加载的图片。这些图片引用位于
CSS
中,预加载扫描器无法发现这些引用
root
:用作窗口的元素,用于检查目标的可见性,如果未指定或为 null,则默认为浏览器窗口。
rootMargin
:根周围的边距
threshold
:一个数字或一个数字数组,表示目标可见度达到多少百分比时,观察器的回调就应该执行。如果只想在能见度超过 50% 时检测,可以使用 0.5 的值。如果希望每次能见度超过 25% 时都执行回调,则需要指定数组 [0, 0.25, 0.5, 0.75, 1]。默认值为 0(这意味着只要有一个像素可见,回调就会运行)。值为 1.0 意味着在每个像素都可见之前,阈值不会被认为已通过。
虽然许多性能涉及到可以采取哪些措施来优化和消除不必要的资源,但建议先加载一些资源才是需要用到的,这似乎有点自相矛盾。不过,在某些情况下,可以提前加载某些资源
可以使用
资源提示提前提取资源(包括图片、样式表或
JavaScript
资源)。
prefetch
提示用于告知浏览器在不久的将来可能需要某个资源
指定
prefetch
提示后,浏览器可能会以最低优先级发起对该资源的请求,以避免与当前页面所需的资源发生争用
预提取资源可以改善用户体验,因为用户无需等待近期所需的资源下载完毕,因为可以在需要时立即从磁盘缓存中检索这些资源
还可以通过在指向某个
HTML
文档时指定
as="document"
属性来预提取网页及其所有子资源
在基于
Chromium
的浏览器中,可以使用
Speculation Rules API
预提取文档。推测规则定义为包含在网页的
HTML
中的
JSON
对象,或通过
JavaScript
动态添加:
除了预提取资源之外,还可以提示浏览器在用户导航到某个网页之前预呈现该网页
这种做法几乎可以即时加载网页,因为系统会在后台提取和处理网页及其资源。当用户导航到相应页面后,系统会将该页面置于前台
Speculation Rules API
支持预渲染:
还可以使用
Service Worker
推测性地预提取资源
Service Worker
预缓存可以使用
CacheAPI
提取和保存资源,这样浏览器无需访问网络即可使用
Cache API
处理请求
Service Worker
预缓存使用一种非常有效的
Service Worker
缓存策略,称为“仅缓存”策略。这种模式非常有效,因为将资源放入
Service Worker
缓存后,可在收到请求时几乎即时提取这些资源
如需使用
Service Worker
预缓存资源,可以使用
Workbox
Workbox
使用预缓存清单来确定应预缓存的资源,预缓存清单是一个文件和版本控制信息列表,可作为要预缓存的资源的可信来源
[{
url: 'script.ffaa4455.js',
revision: null
}, {
url: '/index.html',
revision: '518747aa'
}]
上述代码是一个示例清单,其中包含
script.ffaa4455.js
和
/index.html
这两个文件。如果资源在文件本身中包含版本信息(称为文件哈希),则
revision
属性可以保留为
null
,因为文件已进行版本控制(例如,上述代码中
script.ffaa4455.js
资源的
ffaa4455
属性)。
设置后,
Service Worker
可用于预缓存静态页面或其子资源,以加快后续页面导航的速度
workbox.precaching.precacheAndRoute([
'/styles/product-page.ac29.css',
'/styles/product-page.39a1.js',
]);
Service Worker
使用的
Cache
接口和
HTTP
缓存并不相同
Cache
接口是由
JavaScript
控制的高层级缓存,而
HTTP
缓存是由
Cache-Control
标头控制的低层级缓存
与使用资源提示或推测规则预提取或预呈现资源类似,
Service Worker
预缓存会消耗网络带宽、存储空间和
CPU
建议仅预缓存可能会使用的资源,并在预缓存清单中指定过多的资源
用户在浏览器中看到的大部分内容都在称为主线程的单个线程上完成。不过,在某些情况下,可以启动新线程来执行计算开销很大的工作,以便主线程可以处理面向用户的重要任务。执行此操作的
API
称为
Web Worker API
JavaScript
通常被描述为一种单线程语言。这是指主线程,这是浏览器执行在浏览器中看到的大部分工作的单个线程。其中包括编写脚本、某些类型的渲染工作、
HTML
和
CSS
解析以及其他类型的面向用户的工作来改善用户体验等
就
JavaScript
而言,通常只能在主线程上执行工作,但可以在
JavaScript
中注册和使用其他线程。允许在
JavaScript
中实现多线程的功能称为
Web Workers API
实例化
Worker
类
const myWebWorker = new Worker('/my-web-worker.js');
与在主线程上运行的
JavaScript
不同,
Web Worker
无法直接访问
window上下文
,并且对其提供的
API
的访问受到限制。
Web Worker
受到以下限制条件的约束:
Web Worker
无法直接访问
DOM
Web Worker
可以通过消息传递流水线与
window
上下文进行通信,这意味着
Web Worker
可以通过某种方式间接访问
DOM
Web Worker
的作用域是
self
,而不是
window
Web Worker
范围_确实_可以访问
JavaScript
基元和构造,以及
fetch
等
API
和相当多的其他
API
Web Worker
可以通过消息传递流水线与主线程的
window
上下文进行通信。利用此流水线,可以将数据传送到主线程和
Web
工作器以及从主线程和
Web
工作器传输数据。如需将数据从
Web Worker
发送到主线程,需要在
Web Worker
的上下文 (
self
) 中设置
message
事件
// my-web-worker.js
self.addEventListener("message", () => {
// Sends a message of "Hellow, window!" from the web worker:
self.postMessage("Hello, window!");
});
然后,在主线程上
window
上下文的脚本中,可以使用另一个
message
事件接收来自网页工作器线程的消息:
// scripts.js
// Creates the web worker:
const myWebWorker = new Worker('/js/my-web-worker.js');
// Adds an event listener on the web worker instance that listens for messages:
myWebWorker.addEventListener("message", ({ data }) => {
// Echoes "Hello, window!" to the console from the worker.
console.log(data);
});
mifun 官网版 1.4 50.03 MB
下载
湘ICP备2022002427号-10 湘公网安备:43070202000427号
© 2013~2024 haote.com 好特网