本文会对web页面的全链路进行完整的讲解并针对每一步找到能做的性能优化点,本文的目标是极致的性能优化。
成都创新互联公司咨询热线:18980820575,为您提供成都网站建设网页设计及定制高端网站建设服务,成都创新互联公司网页制作领域十载,包括成都混凝土搅拌机等多个领域拥有多年建站经验,选择成都创新互联公司,为网站锦上添花。
因为针对性能优化,能做的点会特别特别的多,覆盖着整个互联网的访问流程,因此此文章的内容会比较多且杂,笔者会尽量对内容进行分类讲解。
本文的大致流程为先讲理论知识,比如如何评价一个页面的性能好与不好、如果获取性能指标,如何使用各种性能相关工具,浏览器如何获取并渲染页面。笔者认为这些都是基础,只有了解了这些基础才能开始考虑如何去优化。
接下来我们会进入性能优化环节,在这个环节我会详细讲解在页面的整个流程中,哪些地方可以做哪些优化。
1.用户输入
2.卸载原页面并重定向到新页面
3.处理Service Worker
4.网络请求
5.服务端响应
6.浏览器渲染详细流程
我们需要知道浏览器是如何渲染一个页面的,我们才能知道如何对页面进行性能优化,所以这里我们对一些基础知识进行讲解
浏览器有多种进程,其中最主要的5种进程如下
图1
用户在 浏览器进程 输入并按下回车健后,浏览器判断用户输入的url是否为正确的url,如果不是,则使用默认的搜索引擎将该关键字拼接成url。
然后浏览器会将现有页面卸载掉并重定向到用户新输入的url页面,也就是图中【Process Unload Event】和【Redirect】流程。
此时浏览器会准备一个 渲染进程 用于渲染即将到来的页面,和一个 网络进程 用于发送网络请求。
如果当前页面注册了Service Worker那么它可以拦截当前网站所有的请求,进行判断是否需要向远程发送网络请求。也就是图中【Service Worker Init】与【Service Worker Fecth Event 】步骤
如果不需要发送网络请求,则取本地文件。如果需要则进行下一步。
OSI网络七层模型:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
在实际应用中物理层、数据链路层被统称为物理层,会话层、表示层、应用层被统称为应用层,所以实际使用时通常分为4个层级
【物理层】>【网络层(IP)】>【传输层(TCP/UDP)】>【应用层(HTTP)】
也就是图中【HTTP Cache】、【DNS】、【TCP】、【Request】、【Response】步骤
图2
浏览器会拿着url通过 网络进程 进行如下步骤
HTTP/2.0
多路复用
:
hpack
HTTP/3.0 使用UDP实现,在UDP上一层加入一层 QUIC 协议,解决了TCP协议中的队头阻塞问题。
在 4.网络请求 第 6 步中,服务器收到HTTP请求后需要根据请求信息来进行解析,并返回给客户端想要的数据,这也就服务端响应。
服务端可以响应并返回给客户端很多种类型的资源,这里主要介绍 html 类型
目前前端处理服务端响应html请求主要分为SSR服务端渲染与CSR客户端渲染,CSR就是返回一个空的HTML模版,然后浏览器加载js后通过js动态渲染页面。SSR是服务端在接受到请求时事先在服务端渲染好html返回给客户端后,客户端再进行客户端激活。
在打开一个站点的首屏页的完整链路中,使用SSR服务端渲染时的速度要远大于CSR客户端渲染,并且SSR对SEO友好。所以对于首屏加载速度比较敏感或者需要优化SEO的站点来说,使用SSR是更好的选择。
浏览器渲染详细流程主要在 4.网络请求 中的地 7 步。浏览器下载完 html 内容后进行解析何渲染页面的流程。
渲染流程分为4种情况,
下面的流程是对上图的文字版解析。读者可将以上4种情况分别带入到如下的渲染流程中走一遍。就能理解浏览器的完整渲染过程了。
浏览器收到html资源后先预扫描 和 并加载对应资源
对HTML字符串从上到下逐行解析,每解析完成一部分都会拿着解析结果进入下一步骤
css 相关标签跳过此步骤
如果当前解析结果为
相关标签,则生成DOM树( window.document )后进入下一步。如果当前解析结果为 相关标签且并且没有添加异步属性,则先停止【HTML Parser】的进行,等待 资源加载完成后,然后按照以下2种情况处理,当处理完成后便停止当前 标签后续步骤的执行,并继续进行新标签【HTML Parser】步骤的解析
如果当前解析结果为 css 相关标签,则等待其CSS资源加载完成,同时继续进行下一行的【HTML Parser】
当CSS资源加载完毕后,对CSS从上到下逐行解析
当CSS解析完毕后,生成CSS规则树,也叫CSSOM,也就是 window.document.styleSheets
根据DOM树与CSS规则树计算出每个节点的具体样式。
分为两种情况
如果HTML从未解析到过 css 相关标签则使用HTML默认样式,如果已经解析到过 css 相关标签则阻塞等待 css 标签也完成【Attachment】步骤后才进入下一步。
则需要根据是否在之前已经渲染过CSS资源中对应的DOM节点,如果已经渲染过则需要重绘。如果未渲染过任何相关DOM节点则此步骤为最后一步。
生成渲染树,在此阶段已经可以将具体的某个
与对应的CSS样式对应起来了。有了渲染树后浏览器就能根据当前浏览器的状态计算出某个DOM节点的样式、大小、宽度、是否独占一行等信息。计算完成后把一些不需要显示出来的节点在渲染树中删掉。如 display: none 。通过渲染树进行分层(根据定位属性、透明属性、transform属性、clip属性等)生成图层树。
绘制所有图层,并转交给合成线程来最最终的合并所有图层的处理。
最终生成页面并显示到浏览器上
浏览器在渲染完页面之后还需要不间断的处理很多内容的,比如动画、用户事件、定时器等。因此当浏览器渲染完页面后,还会在之后的每一帧到来时执行以下的流程。
了解完浏览器渲染原理,我们还需要知道根据哪些指标才能判断一个页面性能的好坏,在Chrome中这些指标应该怎么获取。以及Chrome都为我们提供了哪些性能相关的工具,如何使用。
Performance既是一个Chrome工具,可用于性能检测。
同样又是一套JS API,可在Chrome中执行。
打开Chrome调试面板选择 Performance ,中文版为 性能 ,点击刷新按钮,Performance会刷新并录制当前页面,然后我们就可以在面板中看到如下的各种性能相关细节。
js中存在Performance API,可用于性能检测,具体如下
接下来我们来了解一下目前常用的性能指标,并且我们需要知道其中一些关键指标如何用Performance API获取。
TTFB(Time To First Byte) : 从发送请求到数据返回第一个字节所消耗的时间
const { responseStart, requestStart } = performance.timing
const TTFB = responseStart - requestStart
FP (First Paint) 首次绘制 : 第一个像素绘制到页面上的时间
const paint = performance.getEntriesByType('paint')
const FP = paint[0].startTime
FCP (First Contentful Paint) 首次内容绘制 标记浏览器渲染来自 DOM 第一位内容的时间点,该内容可能是文本、图像、SVG 甚至 元素.
const paint = performance.getEntriesByType('paint')
const FCP = paint[1].startTime
FMP(First Meaningful Paint) 首次有效绘制 : 例如,在 YouTube 观看页面上,主视频就是主角元素.
图片可以没加载完成,但整体的骨架已经加载完成了。
1秒内完成FMP的概率超过80%,那就代表这个网站是一个性能较好的网站
let FMP = 0
const performanceObserverFMP = new PerformanceObserver((entryList, observer) => {
const entries = entryList.getEntries()
observer.disconnect()
FMP = entries[0].startTime
})
// 需要在元素中添加 elementtiming="meaningful"
performanceObserverFMP.observe({ entryTypes: ['element'] })
TTI (Time to Interactive) 可交互时间 : DOM树构建完毕,可以绑定事件的时间
const { domInteractive, fetchStart } = performance.timing
const TTI = domInteractive - fetchStart
LCP (Largest Contentful Paint) 最大内容渲染 : 代表在viewport中最大的页面元素加载的时间. LCP的数据会通过PerformanceEntry对象记录, 每次出现更大的内容渲染, 则会产生一个新的PerformanceEntry对象.(2019年11月新增)
let LCP = 0
const performanceObserverLCP = new PerformanceObserver((entryList, observer) => {
const entries = entryList.getEntries()
observer.disconnect()
LCP = entries[entries.length - 1].startTime
})
performanceObserverLCP.observe({ entryTypes: ['largest-contentful-paint'] })
DCL (DomContentloaded) : 当 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,无需等待样式表、图像和子框架的完成加载
const { domContentLoadedEventEnd, fetchStart } = performance.timing
const DCL = domContentLoadedEventEnd - fetchStart
L (onLoad) , 当依赖的资源(图片、文件等), 全部加载完毕之后才会触发
const { loadEventStart, fetchStart } = performance.timing
const L = loadEventStart - fetchStart
FID (First Input Delay) 首次输入延迟 : 指标衡量的是从用户首次与您的网站进行交互(即当他们单击链接,点击按钮等)到浏览器实际能够访问之间的时间
let FID = 0
const performanceObserverFID = new PerformanceObserver((entryList, observer) => {
const entries = entryList.getEntries()
observer.disconnect()
FID = entries[0].processingStart - entries[0].startTime
})
performanceObserverFID.observe({ type: ['first-input'], buffered: true })
TBT (Total Blocking Time) 页面阻塞总时长 : TBT汇总所有加载过程中阻塞用户操作的时长,在FCP和TTI之间任何long task中阻塞部分都会被汇总
CLS (Cumulative Layout Shift) 累积布局偏移 : 总结起来就是一个元素初始时和其hidden之间的任何时间如果元素偏移了, 则会被计算进去, 具体的计算方法可看这篇文章 https://web.dev/cls/
SI (Speed Index) : 指标用于显示页面可见部分的显示速度, 单位是时间
获取代码未使用占比
获取性能报告并查看推荐优化项
可以在本地安装命令行工具来使用,也可以通过Chrome来使用。
命令行方式使用
npm install -g lighthouse
lighthouse --view https://m.baidu.com
在Chrome中使用
能获取网络请求的时间消耗细节,可以根据耗时来决定优化策略。优先优化耗时最长的
【正在排队】网络请求队列的排队时间
【已停止】阻塞住用于处理其他事情的时间
【DNS查找】用于DNS解析IP地址的时间
【初始连接】创建TCP连接时间
【SSL】用于SSL协商的时间
【已发送请求】用于发送请求的时间
【等待中】请求发出至接收响应的时间也可以理解为服务端处理请求的时间
【下载内容】下载响应的时间
浏览器会根据资源的类型决定优先请求哪些资源,优先级高的请求能够优先被加载。
右击此处勾选优先级可打开优先级功能,在请求中便可看到网络请求的优先级
不同资源类型的优先级排序如下
【最高】html、style
【高】font、fetch、script
【低】image、track
【58个请求】网页一共多少个请求
【6.9 MB 项资源】网页资源一共6.9MB大小
【DOMContentLoaded:454 毫秒】DOM加载完毕的时长
【加载时间:1.02 秒】onload完毕的时长
上面我们分别讲解了进程与线程、浏览器打开一个页面的完整过程、浏览器处理每一帧时的流程、Chrome性能相关的各种工具以及性能相关的各种指标。以上内容都掌握之后我们再考虑性能优化遍有了思路,我们在页面展示的任意一个步骤中对其进行优化都能对整个网页的展示性能产生影响。
下面列出了一个页面能优化的所有内容,读者可根据自己的业务情况结合性能工具来做适合自己的优化方式。
合并JS、合并CSS、合理内嵌JS和CSS、使用雪碧图
使用强制缓存可以不走网络请求,直接走本地缓存数据来加载资源。
使用协商缓存可以减少数据传输,当不需要更新数据时可通知客户端直接使用本地缓存。
HTTP/2.0使用同一个TCP连接来发送数据,他把多个请求通过二进制分贞层实现了分贞,然后把数据传输给服务器。也叫 多路复用 ,多个请求复用同一个TCP连接。
HTTP/2.0会将所有以 : 开头的请求头做一个映射表,然后使用 hpack 进行压缩,使用这种方式会使请求头更小。
服务器可主动推送数据给客户端。
301、302 重定向会降低响应速度
DNS请求虽然占用的带宽较少,但会有很高的延迟,由其在移动端网络会更加明显。
使用dns-prefetch可以对网站中使用到的域名提前进行解析。提高资源加载速度。
通过dns预解析技术可以很好的降低延迟,在访问以图片为主的移动端网站时,使用DNS预解析的情意中下页面加载时间可以减少5%。
在HTTP/1.1中,一个域名同时最多创建6个TCP连接,将资源放在多个域名下可提高请求的并发数
静态资源全上CDN,CDN能非常有效的加快网站静态资源的访问速度。
gzip压缩、html压缩、js压缩、css压缩、图片压缩
contenthash可以根据文件内容在文件名中加hash,可用于浏览器缓存文件,当文件没有改变时便直接取本地缓存数据
preload预加载、prefetch空闲时间加载
两者都不会阻塞 onload 事件, prefetch 会在页面空闲时候再进行加载,是提前预加载之后可能要用到的资源,不一定是当前页面使用的, preload 预加载的是当前页面的资源。
Document
如上代码,预加载了css但并没有使用。浏览器在页面 onload 完成一段时间后,发现还没有引用预加载的资源时,浏览器会在控制台输出下图的提示信息
preload和prefetch可根据资源类型决定资源加载的优先级,详细优先级如代码
Document
当通过JS或者其他任意方式修改DOM后,浏览器会进入如下流程
【JS通过API修改DOM】>【计算样式】>【布局(重排)】>【绘制(重绘)】>【合成】
Reflow 重排 :重排在Chrome Performance中叫做布局,通常添加或删除元素、修改元素大小、移动元素位置、获取位置信息都会触发页面的重排,因为重排可能会改变元素的大小位置等信息,这样的改变会影响到页面大量其它元素的大小位置信息,会耗费掉大量的性能,所以在实际应用中我们应该尽可能的减少重排
Repaint 重绘 :重绘在Chrome Performance中叫做绘制,通常样式改变但没有影响位置时会触发重绘操作,重绘性能还好,但我们也需要尽量减少重绘,如果需要做一些动画,我们尽量使用CSS3动画,CSS3动画只需要在初始化时绘制一次,之后的动画都不会触发重绘操作。
在同一个函数内,修改元素后又获取元素的位置时会触发强制同步布局,影响渲染性能
强制同步布局会使js强制将【计算样式】和【布局(重排)】操作提前到当前函数任务中,这样会导致每次运行时执行一次【计算样式】和【重排】,这样一定会影响页面渲染性能,而正常情况下【计算样式】和【重排】操作会在函数结束后统一执行。
Document
在函数运行时执行了10次【计算样式】和【重排】
反复触发强制同步布局也叫 布局抖动
分享题目:Web页面全链路性能优化指南
当前路径:http://www.mswzjz.cn/qtweb/news34/106134.html攀枝花网站建设、攀枝花网站运维推广公司-贝锐智能,是专注品牌与效果的网络营销公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 贝锐智能