一文带你认识,前端性能指标&优化哪些事
<h1 style="color: black; text-align: left; margin-bottom: 10px;">前端性能指标&优化</h1>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">参考资料</h1><span style="color: black;">从输入 URL 到页面展示到底<span style="color: black;">出现</span>了什么?</span><span style="color: black;">Web 指标-Google</span><span style="color: black;">关于 cdn、回源等问题一网打尽</span><span style="color: black;">前端性能优化之 rel=“prefetch“预/懒加载功能</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">前置知识</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">从一个经典的面试题引出<span style="color: black;">文案</span>内容: </span><strong style="color: blue;"><span style="color: black;">输入 url 到页面<span style="color: black;">最后</span>呈现都<span style="color: black;">出现</span>了什么?</span></strong></p><span style="color: black;">URL 解析</span><span style="color: black;">判断输入是搜索关键字还是 url <span style="color: black;">位置</span>,对 url 解析</span><span style="color: black;">DNS 域名解析获取 IP <span style="color: black;">位置</span></span><span style="color: black;">缓存<span style="color: black;">查询</span>:浏览器缓存(chrome://net-internals/#dns)->系统缓存(host)->路由器缓存->运营商缓存(IPS)->根域名服务器</span><span style="color: black;">向本地 DNS 服务器发送<span style="color: black;">查找</span>报文"query zh.wikipedia.org"</span><span style="color: black;">本地 DNS 服务器<span style="color: black;">检测</span><span style="color: black;">自己</span>缓存,存在返回,不存在向根域名服务器发送<span style="color: black;">查找</span>报文"query zh.wikipedia.org",得到顶级域 .org 的顶级域名服务器<span style="color: black;">位置</span></span><span style="color: black;">DNS 服务器向 .org 域的顶级域名服务器发送<span style="color: black;">查找</span>报文"query zh.wikipedia.org",得到二级域 .wikipedia.org 的权威域名服务器<span style="color: black;">位置</span></span><span style="color: black;">DNS 服务器向 .wikipedia.org 域的权威域名服务器发送<span style="color: black;">查找</span>报文"query zh.wikipedia.org",得到主机 zh 的 A 记录,存入<span style="color: black;">自己</span>缓存并返回给客户端</span><span style="color: black;">拓展方向:什么是 CDN?、CDN 回源?</span><span style="color: black;"><span style="color: black;">按照</span> IP <span style="color: black;">位置</span><span style="color: black;">创立</span> TCP 链接(三次握手)</span><span style="color: black;">三次挥手<span style="color: black;">重点</span>是为了</span><span style="color: black;"><span style="color: black;">双方确认过信息,<span style="color: black;">能够</span><span style="color: black;">创立</span>起通信</span></span>,见图 1抽象一点的话,这个过程<span style="color: black;">能够</span>想象成两个人分别站在<span style="color: black;"><span style="color: black;">山谷的两边</span></span>,想要<span style="color: black;"><span style="color: black;">相互聊天</span></span>,<span style="color: black;">然则</span>又不确定自己喊一嗓子之后对方到底能<span style="color: black;">不可</span>听到,<span style="color: black;">而后</span>就双方<span style="color: black;">起始</span>聊天之前先互相喊几嗓子,确认一下双方是不是都<span style="color: black;">能够</span>听到<span style="color: black;"><span style="color: black;">第1</span>次:主机 A 发给 B 一个标识位 SYN,<span style="color: black;">期盼</span><span style="color: black;">经过</span>该数据告诉主机 B <span style="color: black;">创立</span>连接相当于 A 想找 B 聊天,就喊了一个 x 给 B</span><span style="color: black;">第二次:主机 B <span style="color: black;">经过</span>一个确认应答的 ACK 和同步序列号 SYN 响应给 A,<span style="color: black;">这般</span>主机 A <span style="color: black;">经过</span> ACK 就<span style="color: black;">晓得</span>主机 B 接收到了<span style="color: black;">第1</span>次的握手的数据,并且主机 A <span style="color: black;">经过</span>响应的 SYN <span style="color: black;">晓得</span>了要从那个序列号做标记相当于 B 听到了 A 喊的 x,<span style="color: black;">晓得</span> A 想聊天,</span><span style="color: black;"><span style="color: black;">B不<span style="color: black;">晓得</span>A能<span style="color: black;">不可</span>听到自己说话</span></span>,<span style="color: black;">而后</span> B 就把 A <span style="color: black;">第1</span>次的 x 和自己想说的话 y <span style="color: black;">一块</span>喊给了 A<span style="color: black;">第三次:主机 A 发送主机 B 响应的 SYN+1,<span style="color: black;">这般</span>主机 B 就<span style="color: black;">晓得</span>主机 A 收到了自己的信息,后面就<span style="color: black;">能够</span>传输数据了<span style="color: black;">而后</span> A 收到了<span style="color: black;">第1</span>次喊话的 x+1,<span style="color: black;">这般</span></span><span style="color: black;"><span style="color: black;">A就确认了B<span style="color: black;">能够</span>听到自己的话</span></span>,<span style="color: black;">而后</span> A 再把 B 说的话 y+1 喊给 B,<span style="color: black;">这般</span><span style="color: black;"><span style="color: black;">B收到A的信息之后就<span style="color: black;">晓得</span>A<span style="color: black;">能够</span>听到自己的话</span></span>,后面双方就<span style="color: black;">能够</span>愉快的聊天了<span style="color: black;">发送 http 请求,服务器响应,缓存判断(强缓存|协商缓存)</span><span style="color: black;">请求:发送命令+发送请求头信息+空白行+请求体(post)</span><span style="color: black;">响应:响应状态 + 响应头+空白行+响应体</span><span style="color: black;">强缓存:cache-control(max-age)、Expires</span><span style="color: black;">协商缓存:返回 ETag、Last-modified 和请求 IF-none-match、IF-modified-since</span><span style="color: black;">浏览器解析响应内容并渲染页面,见图 2</span><span style="color: black;">解析 HTML,生成 DOM 树</span><span style="color: black;">解析 CSS,生成 CSSOM(CSS Object Model)</span><span style="color: black;">合并 DOM 树和 CSSOM,生成 Render 树</span><span style="color: black;"><span style="color: black;">而后</span>交给 Layout 引擎,<span style="color: black;">按照</span> Render 树信息,获取节点的元素<span style="color: black;">体积</span>和位置等布局信息</span><span style="color: black;"><span style="color: black;">而后</span>交给 Paint 引擎,绘制页面像素信息,<span style="color: black;">表示</span>在屏幕上</span><span style="color: black;">这个过程并不是一次性完成的,而是可能存在</span><span style="color: black;"><span style="color: black;">重复</span></span>或<span style="color: black;"><span style="color: black;">交叉</span></span>的<span style="color: black;">状况</span>,<span style="color: black;">例如</span>当遇到 JavaScript <span style="color: black;">或</span>动态资源时,可能需要重新构建或更新某些部分。<span style="color: black;">拓展方向:重排、重绘重排(reflow):元素的几何尺寸<span style="color: black;">出现</span>变化需要重新计算元素在页面中的位置和<span style="color: black;">体积</span>,这个过程会交给 Layout 引擎,<span style="color: black;">引起</span>整颗 Render 树重新计算,开销<span style="color: black;">很强</span>重绘(repaint):元素的外观(颜色、背景、边框)<span style="color: black;">出现</span>变化,浏览器需要重新绘制,这个过程触及到 Paint 引擎,直接绘制,执行效率比重排高</span><span style="color: black;">连接结束关闭 TCP 链接(四次挥手)</span><span style="color: black;">抽象层面理解的话,就好比男女<span style="color: black;">伴侣</span>分手</span><span style="color: black;"><span style="color: black;">第1</span>次:男方想分手,就给女方发一个 FIN 包(<span style="color: black;">暗示</span>结束),并等待女方的回答</span><span style="color: black;">第二次:女方收到了男方的 FIN 包,就给男方回复了一个 ACK 包(<span style="color: black;">暗示</span>确认),告诉他“我<span style="color: black;">晓得</span>你想分手了”,<span style="color: black;">然则</span>女方还有<span style="color: black;">有些</span>话想说,不会马上同意分手(<span style="color: black;">暗示</span>服务器需要时间处理关闭的<span style="color: black;">规律</span>)</span><span style="color: black;">第三次:女方说完了自己的话(关闭<span style="color: black;">规律</span>处理结束),就给男方发一个 FIN 包(表结束),<span style="color: black;">暗示</span>自己<span style="color: black;">亦</span>同意分手了,并等待男方的<span style="color: black;">回复</span></span><span style="color: black;">第四次:男方收到了 FIN 包,就给女方回一个 ACK 包(表确认),<span style="color: black;">暗示</span>自己<span style="color: black;">亦</span>同意分手了,并且俩人<span style="color: black;">再也不</span>有话说。<span style="color: black;">这般</span>女方听到之后俩人就正式断开了链接</span>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p26-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/ce14262113484db3a8991e47e1dd9257~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1728744254&x-signature=owFL9s6k%2Fa0iuDLF1lGkGo%2BtSUA%3D" style="width: 50%; margin-bottom: 20px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">三次握手与四次挥手</p>
</div>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/4867e64893004668a55519aa3b0f3fa4~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1728744254&x-signature=KGuo64VFWkbhm5G53IXS7jjY2qo%3D" style="width: 50%; margin-bottom: 20px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">浏览器解析响应内容并渲染页面</p>
</div>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">拓展方向</h1>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">TCP 与 UDP 的区别?</h1><span style="color: black;">TCP:</span><span style="color: black;">TCP 协议则是</span><span style="color: black;"><span style="color: black;"><span style="color: black;">创立</span>在IP协议</span></span>之上的。TCP 协议负责在两台计算机之间<span style="color: black;">创立</span><span style="color: black;"><span style="color: black;">可靠</span></span>连接,<span style="color: black;">保准</span>数据包按<span style="color: black;"><span style="color: black;"><span style="color: black;">次序</span></span></span>到达。<span style="color: black;">TCP 协议会<span style="color: black;">经过</span></span><span style="color: black;"><span style="color: black;">三次握手</span></span><span style="color: black;">创立</span>连接,<span style="color: black;">而后</span>,对<span style="color: black;">每一个</span> IP 包编号,<span style="color: black;">保证</span>对方按<span style="color: black;">次序</span>收到,<span style="color: black;">倘若</span>包丢掉了,就自动重发。<span style="color: black;">许多常用的更高级的协议都是<span style="color: black;">创立</span>在 TCP 协议<span style="color: black;">基本</span>上的,<span style="color: black;">例如</span>用于浏览器的</span><span style="color: black;"><span style="color: black;">HTTP</span></span>协议、发送邮件的<span style="color: black;"><span style="color: black;">SMTP</span></span>协议等。<span style="color: black;">一个 TCP 报文除了<span style="color: black;">包括</span>要传输的数据外,还<span style="color: black;">包括</span>源 IP <span style="color: black;">位置</span>和<span style="color: black;">目的</span> IP <span style="color: black;">位置</span>,源端口和<span style="color: black;">目的</span>端口。</span><span style="color: black;">UDP:</span><span style="color: black;">UDP 则是</span><span style="color: black;"><span style="color: black;">面向无连接</span></span>的协议,TCP 必须<span style="color: black;">创立</span><span style="color: black;">靠谱</span>的连接<span style="color: black;"><span style="color: black;">运用</span> UDP 协议时,</span><span style="color: black;"><span style="color: black;">不需要<span style="color: black;">创立</span>连接</span></span>,只需要<span style="color: black;">晓得</span>对方的 IP <span style="color: black;">位置</span>和端口号,就<span style="color: black;">能够</span>直接发数据包。<span style="color: black;">然则</span>,能<span style="color: black;">不可</span>到达就不<span style="color: black;">晓得</span>了。<span style="color: black;">因此</span> UDP 传输的数据<span style="color: black;"><span style="color: black;">不<span style="color: black;">靠谱</span></span></span><span style="color: black;">UDP 是</span><span style="color: black;"><span style="color: black;">面向报文</span></span>的,<span style="color: black;">无</span>拥塞<span style="color: black;">掌控</span>,<span style="color: black;">因此</span>速度快,比较多<span style="color: black;">媒介</span>通讯,<span style="color: black;">如:聊天和视频,支持一对<span style="color: black;">1、</span>一对多、多对<span style="color: black;">1、</span>多对多,如浏览器上的视频聊天</span><span style="color: black;"><span style="color: black;">然则</span><span style="color: black;">此刻</span><span style="color: black;">平常</span>的直播服务,为了<span style="color: black;">供给</span></span><span style="color: black;"><span style="color: black;">稳定</span></span>的直播环境,都是采用的 TCP 链接<h1 style="color: black; text-align: left; margin-bottom: 10px;">HTTP1.0、1.1、2.0 的区别?</h1><span style="color: black;">1.0</span><span style="color: black;">每次 tcp 连接只能发送</span><span style="color: black;"><span style="color: black;">一个</span></span>请求,当服务器响应后就会关闭这次连接,下一个请求需要<span style="color: black;"><span style="color: black;">再次<span style="color: black;">创立</span></span></span>TCP 连接<span style="color: black;">1.1</span><span style="color: black;">默认采用</span><span style="color: black;"><span style="color: black;"><span style="color: black;">连续</span>链接</span></span>(TCP 链接默认不关闭,<span style="color: black;">能够</span>被多个请求复用,<span style="color: black;">不消</span>声明 Connection:keep-alive)<span style="color: black;"><span style="color: black;">增多</span>了</span><span style="color: black;"><span style="color: black;">管道机制</span></span>,在同一个 TCP 连接里,浏览器<span style="color: black;">准许</span>多个请求<span style="color: black;">同期</span>发送,<span style="color: black;">增多</span>了并发性,进一步改善了 HTTP 协议的效率<span style="color: black;"><span style="color: black;">然则</span>在同一个 TCP 连接里,所有的数据通信是按</span><span style="color: black;"><span style="color: black;"><span style="color: black;">秩序</span></span></span>进行的。<span style="color: black;">倘若</span>前面有一个请求<span style="color: black;">回复</span>慢,就会有许多请求排队,<span style="color: black;">导致</span><span style="color: black;"><span style="color: black;">“队头堵塞”</span></span><span style="color: black;">2.0</span><span style="color: black;">加了</span><span style="color: black;"><span style="color: black;">双工模式</span></span>,即:不仅客户端能够<span style="color: black;">同期</span>发送多个请求,服务端<span style="color: black;">亦</span>能<span style="color: black;">同期</span>处理多个请求,<span style="color: black;">处理</span>了队头堵塞的问题<span style="color: black;"><span style="color: black;">运用</span>了</span><span style="color: black;"><span style="color: black;">多路复用</span></span>的技术,做到<span style="color: black;"><span style="color: black;">同一个连接并发处理多个请求</span></span>,<span style="color: black;">况且</span>并发请求数量比 http1.1 大了好几个数量级<span style="color: black;">增加服务器推送的功能,不经请求,服务端主动向客户端发送数据</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">HTTP1.1 长连接和 2.0 多路复用的区别?</h1><span style="color: black;">长连接:同一时间一个 TCP 连接只能处理一个请求,采用</span><span style="color: black;"><span style="color: black;">一问一答</span></span>的形式,上一个请求响应后<span style="color: black;">才可</span>处理下一个请求,<span style="color: black;">因为</span><span style="color: black;"><span style="color: black;">浏览器有最大TCP连接的限制</span></span>(6 个),<span style="color: black;">因此</span>有了最大并发请求数的限制。<span style="color: black;">多路复用:同域名下所有的通信都在</span><span style="color: black;"><span style="color: black;">单个TCP</span></span>连接上完成,消除了因多个 TCP 连接而带来的延时和内存消耗。单个连接上<span style="color: black;">能够</span><span style="color: black;"><span style="color: black;">并行</span></span>的请求和响应,之前互不干扰<h1 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">为何</span> HTTP1.1 <span style="color: black;">不可</span>实现多路复用?</h1><span style="color: black;">http2.0 是基于</span><span style="color: black;"><span style="color: black;">二进制"帧"</span></span>的概念,http1.1 是基于<span style="color: black;"><span style="color: black;">“文本分割”</span></span>解析的协议<span style="color: black;">在 http1.1 的报文结构中,服务器需要<span style="color: black;">持续</span>的读入字节,直到遇到</span><span style="color: black;"><span style="color: black;">换行符(br)</span></span>,<span style="color: black;">或</span>说是空白行。处理<span style="color: black;">次序</span>是<span style="color: black;"><span style="color: black;">串行</span></span>的,一个请求和一个响应需要<span style="color: black;">经过</span><span style="color: black;"><span style="color: black;">一问一答</span></span>的形式<span style="color: black;">才可</span>对应起来<span style="color: black;">http2.0 中,有两个非常重要的概念,分别是</span><span style="color: black;"><span style="color: black;">“帧”和“流”</span></span><span style="color: black;">帧:<span style="color: black;">表率</span>着最小的</span><span style="color: black;"><span style="color: black;">数据单位</span></span>,<span style="color: black;">每一个</span>帧会标识出该帧属于哪个流,流<span style="color: black;">亦</span><span style="color: black;">便是</span>帧<span style="color: black;">构成</span>的数据流<span style="color: black;">多路复用:<span style="color: black;">便是</span>在每一个</span><span style="color: black;"><span style="color: black;">TCP连接中<span style="color: black;">能够</span>存在多条流</span></span>。<span style="color: black;">换句话说,<span style="color: black;">亦</span><span style="color: black;">便是</span><span style="color: black;">能够</span>发送多个请求,<span style="color: black;">能够</span><span style="color: black;">经过</span></span><span style="color: black;"><span style="color: black;">帧中的标识</span></span><span style="color: black;">晓得</span>属于哪个请求<span style="color: black;"><span style="color: black;">经过</span>这个技术,<span style="color: black;">能够</span>避免 HTTP 就版本中的</span><span style="color: black;"><span style="color: black;">队头堵塞</span></span>问题,<span style="color: black;">极重</span>的<span style="color: black;">加强</span>传输性能<h1 style="color: black; text-align: left; margin-bottom: 10px;">什么是 CDN?、CDN 回源?</h1><span style="color: black;">CDN 是</span><span style="color: black;"><span style="color: black;">内容分发网络</span></span>的缩写,它是一种将互联网内容快速传输给用户的技术。CDN <span style="color: black;">经过</span>在<span style="color: black;">区别</span>地区<span style="color: black;">安排</span>多个服务器,将内容缓存到离用户<span style="color: black;">近期</span>的服务器上,从而<span style="color: black;"><span style="color: black;">减少延迟和带宽</span></span>消耗。<span style="color: black;">CDN 回源<span style="color: black;">指的是</span>当 CDN 节点<span style="color: black;">无</span>缓存用户请求的内容时,需要向源站(原始服务器)请求资源,并</span><span style="color: black;"><span style="color: black;">重新设置缓存</span></span>的过程。回源<span style="color: black;">能够</span><span style="color: black;">保准</span> CDN 节点总是能够<span style="color: black;">供给</span>最新和最完整的内容给用户,但<span style="color: black;">亦</span>会<span style="color: black;">增多</span>源站的负载和流量成本。<h1 style="color: black; text-align: left; margin-bottom: 10px;">JS 中的垃圾回收机制(GC)</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">垃圾回收是一站自动管理内存的机制,js 中的 gc <span style="color: black;">重点</span>有两种算法:引用计数、标记清除</span></p><span style="color: black;">引用计数:比较早的算法</span><span style="color: black;">记录<span style="color: black;">每一个</span>对象被引用的次数,当一个对象的引用次数为零时,就<span style="color: black;">能够</span>被释放</span><span style="color: black;">缺点:<span style="color: black;">没法</span>处理循环引用的<span style="color: black;">状况</span></span><span style="color: black;">当两个或多个对象相互引用时,<span style="color: black;">她们</span>的引用计数永远不会为零 循环引用例子:</span><span style="color: black;">var</span>a = {};<span style="color: black;">var</span> b = {};
a.b = b;
b.a = a;<span style="color: black;">标记清除:常用的算法,<span style="color: black;">能够</span>处理循环引用问题</span><span style="color: black;">遍历所有的对象,标记<span style="color: black;">哪些</span></span><span style="color: black;"><span style="color: black;"><span style="color: black;">达到</span></span></span>的对象,<span style="color: black;">而后</span>清除<span style="color: black;">哪些</span>不<span style="color: black;">达到</span>的对象<span style="color: black;"><span style="color: black;">这般</span>即使<span style="color: black;">出现</span>循环引用,<span style="color: black;">然则</span>当<span style="color: black;">她们</span>都不<span style="color: black;">达到</span>了,就会被标记清除算法回收</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">标记清除处理循环引用的例子:</span></p><span style="color: black;">var</span> a = {};
<span style="color: black;">var</span>b = {};
a.b = b;
b.a = a;
a =<span style="color: black;">null</span>;
b = <span style="color: black;">null</span>;<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">这儿</span>,对象 a 和对象 b 互相引用,但在最后两行,它们都被赋值为 null,<span style="color: black;">再也不</span>被任何变量引用。 <span style="color: black;">倘若</span><span style="color: black;">运用</span>引用计数算法,它们的引用计数仍然为 1,不会被回收。 但<span style="color: black;">倘若</span><span style="color: black;">运用</span>标记清除算法,它会从全局对象 window)<span style="color: black;">做为</span>根<span style="color: black;">起始</span>遍历所有的对象,<span style="color: black;">发掘</span> a 和 b 都不<span style="color: black;">达到</span>了(<span style="color: black;">由于</span><span style="color: black;">无</span>任何变量指向它们),就会把它们标记为垃圾,并在下一次 gc 时清除它们。</span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">检测工具</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">原理:<span style="color: black;">便是</span>在合适的<span style="color: black;">机会</span>,打上合适的时间戳,<span style="color: black;">或</span>暴露出事件。<span style="color: black;">而后</span><span style="color: black;">经过</span>这些时间戳之间的差值,得出⼀个耗时时间。这个耗时时间就<span style="color: black;">能够</span>反映出<span style="color: black;">咱们</span>⻚⾯的<span style="color: black;">关联</span>性能。工具如下:</span></p><span style="color: black;">API: window.performance</span><span style="color: black;">性能监测对象:PerformanceObserver.observe()</span><span style="color: black;">npm 包:web-vitals</span><span style="color: black;"><span style="color: black;">研发</span>者工具:Lighthouse</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">1.Performance</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Performance 接口<span style="color: black;">能够</span>获取到当前页面中与性能<span style="color: black;">关联</span>的信息。它是 High Resolution Time API 的一部分,<span style="color: black;">同期</span><span style="color: black;">亦</span>融合了 Performance Timeline API、Navigation Timing API、 User Timing API和 Resource Timing API。</span></p><span style="color: black;">User Timing API :⽤户⾃⼰定义在代码中<span style="color: black;">经过</span>调⽤ performance.mark(key) ⽅法定义的时间点。</span><span style="color: black;">Navigation Timing API : 资源请求的时间戳。</span><span style="color: black;">Navigation Timing API :它⾥⾯<span style="color: black;">包括</span>的是<span style="color: black;">咱们</span>从请求<span style="color: black;">起始</span>,到<span style="color: black;">全部</span>⻚⾯的完全<span style="color: black;">表示</span>的各个<span style="color: black;">周期</span>的时间点,包 含了以下:</span>
<div style="color: black; text-align: left; margin-bottom: 10px;">
<div style="color: black; text-align: left; margin-bottom: 10px;">
<div style="color: black; text-align: left; margin-bottom: 10px;">
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">key 值</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">value 值解释</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">navigationStart</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当前浏览器窗⼝的前⼀个⽹⻚关闭,发⽣ unload 事件时的时间戳。<span style="color: black;">倘若</span><span style="color: black;">无</span>前⼀个⽹⻚,就等于 fetchStart(<span style="color: black;">亦</span><span style="color: black;">便是</span>输⼊ URL <span style="color: black;">起始</span>,第⼀步<span style="color: black;">便是</span>卸载上个⻚⾯)</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">redirectStart</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">第⼀次重定向<span style="color: black;">起始</span>时的时间戳,<span style="color: black;">倘若</span><span style="color: black;">无</span>重定向,<span style="color: black;">或</span>上次重定向不是同源的,则为 0</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">redirectEnd</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">最后⼀次重定向完成,<span style="color: black;">亦</span><span style="color: black;">便是</span> Http 响应的最后⼀个字节返回时的时间戳,<span style="color: black;">倘若</span><span style="color: black;">无</span>重定向,<span style="color: black;">或</span>上次重定向不是同源的,则为 0</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">fetchStart</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">浏览器准备<span style="color: black;">经过</span> HTTP 请求去获取⻚⾯的时间戳。在<span style="color: black;">检测</span>应⽤缓存之前<span style="color: black;">出现</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">domainLookupStart</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">域名<span style="color: black;">查找</span><span style="color: black;">起始</span>时的时间戳。<span style="color: black;">倘若</span>使⽤持久连接,<span style="color: black;">或</span>从本地缓存获取信息的,等同于 fetchStart</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">domainLookupEnd</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">域名<span style="color: black;">查找</span>结束时的时间戳。<span style="color: black;">倘若</span>使⽤持久连接,<span style="color: black;">或</span>从本地缓存获取信息的,等同于 fetchStart</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">connectStart</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">HTTP 请求<span style="color: black;">起始</span>向服务器发送时的时间戳,<span style="color: black;">倘若</span>是持久连接,则等同于 fetchStart</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">connectEnd</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">浏览器与服务器之间的连接建⽴时的时间戳,连接建⽴指的是所有握⼿和认证过程<span style="color: black;">所有</span>结束</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">requestStart</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">浏览器向服务器发出 HTTP 请求时(或<span style="color: black;">起始</span>读取本地缓存时)的时间戳</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">responseEnd</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">浏览器从服务器收到(或从本地缓存读取)最后⼀个字节时(<span style="color: black;">倘若</span><span style="color: black;">这里</span>之前 HTTP 连接<span style="color: black;">已然</span>关闭,则返回关闭时)的时间戳</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">domLoading</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当前⽹⻚ DOM 结构<span style="color: black;">起始</span>解析时,<span style="color: black;">亦</span><span style="color: black;">便是</span> document.readyState 属性变为“loading”、并且相应的 readystatechange 事件触发时的时间戳</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">domInteractive</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当前⽹⻚ DOM 结构结束解析</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">domContentLoadedEventStart</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当前⽹⻚ DOMContentLoaded 事件发⽣时,<span style="color: black;">亦</span><span style="color: black;">便是</span> DOM 结构解析完毕、所有脚本<span style="color: black;">起始</span>运⾏时的时间戳</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">domContentLoadedEventEnd</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当前⽹⻚ DOMContentLoaded 事件发⽣时,<span style="color: black;">亦</span><span style="color: black;">便是</span> DOM 结构解析完毕、所有脚本运⾏完成时的时间戳</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">domComplete</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当前⽹⻚ DOM 结构⽣成时,<span style="color: black;">亦</span><span style="color: black;">便是</span> Document.readyState 属性变为“complete”</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">loadEventStart</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当前⽹⻚ load 事件的回调函数<span style="color: black;">起始</span>时的时间戳。<span style="color: black;">倘若</span>该事件还<span style="color: black;">无</span>发⽣,返回 0</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">loadEventEnd</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">当前⽹⻚ load 事件的回调函数结束时的时间戳。<span style="color: black;">倘若</span>该事件还<span style="color: black;">无</span>发⽣,返回 0</p>
</div>
</div>
</div>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">2.performanceObserver</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">PerformanceObserver.observe() :指定监测的 </span></span><span style="color: black;"><span style="color: black;">entryTypes</span></span> 的集合。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">当 performance entry 被记录并且<span style="color: black;">指的是</span>定的 </span><span style="color: black;"><span style="color: black;">entryTypes</span></span>之⼀的时候,性能观察者对象的回调函数会被调⽤。</p><span style="color: black;">var</span> observer = <span style="color: black;">new</span> PerformanceObserver(callback);
<span style="color: black;">// 直接往 PerformanceObserver() 入参匿名回调函数</span>
<span style="color: black;">// 成功 new 了一个 PerformanceObserver 类的,名为 observer 的对象</span>
<span style="color: black;">var</span>observer =<span style="color: black;">new</span> PerformanceObserver(<span style="color: black;"><span style="color: black;">function</span> <span style="color: black;">(list, obj)</span> </span>{
<span style="color: black;">var</span> entries = <span style="color: black;">list</span>.getEntries();
<span style="color: black;">for</span> (<span style="color: black;">var</span> i = <span style="color: black;">0</span>; i < entries.length; i++) {
<span style="color: black;">//处理“mark”和“frame”事件</span>}
});<span style="color: black;">//调用 observer 对象的 observe() <span style="color: black;">办法</span></span>
observer.observe({ entryTypes: [<span style="color: black;">mark</span>, <span style="color: black;">frame</span>] });<h1 style="color: black; text-align: left; margin-bottom: 10px;">3.web-vitals</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">⽬前只能统计CLS | FCP | FID | LCP | TTFB 。<span style="color: black;">倘若</span>需要扩充的话,就<span style="color: black;">能够</span>使⽤上⾯的 Performance 进⾏更改</span></p><span style="color: black;">import</span> { getCLS, getFID, getLCP } <span style="color: black;">from</span> <span style="color: black;">web-vitals</span>;
getCLS(<span style="color: black;">console</span>.log);
getFID(<span style="color: black;">console</span>.log);
getLCP(<span style="color: black;">console</span>.log);
<span style="color: black;">// ...</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">4.Lighthouse</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">运用</span><span style="color: black;">研发</span>者工具中的</span><span style="color: black;"><span style="color: black;">Lighthouse</span></span>Tab <span style="color: black;">或</span><span style="color: black;">运用</span> Node CLI 的方式</p><span style="color: black;">npm</span> <span style="color: black;">install -g lighthouse</span>
<span style="color: black;">lighthouse</span> <span style="color: black;"><url></span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">性能指标</h1>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">1.白屏时间 FP</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">输入 URL <span style="color: black;">起始</span>,到页面<span style="color: black;">起始</span>有变化,只要有任意像素点的变化,就算是白屏时间完结</span></p><span style="color: black;"><span style="color: black;">function</span> <span style="color: black;">getFP</span>() </span>{
<span style="color: black;">new</span> PerformanceObserver(<span style="color: black;">(<span style="color: black;">entryList, observer</span>) =></span> {
<span style="color: black;">let</span> entries = entryList.getEntries();
<span style="color: black;">for</span> (<span style="color: black;">let</span> i = <span style="color: black;">0</span>; i < entries.length; i++) {
<span style="color: black;">if</span> (entries.name === <span style="color: black;">first-paint</span>) {
<span style="color: black;">console</span>.log(<span style="color: black;">FP</span>, entries.startTime);
}
}
}).observe({ <span style="color: black;">entryTypes</span>: [<span style="color: black;">paint</span>] });
}<h1 style="color: black; text-align: left; margin-bottom: 10px;">2.首次内容绘制时间 FCP</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">指的是⻚⾯上绘制了第⼀个元素的时间</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">FP 与 FCP 的最⼤的区别就在于:FP 指的是绘制像素,⽐如说⻚⾯的背景⾊是灰⾊的,<span style="color: black;">那样</span>在<span style="color: black;">表示</span>灰⾊背景时就记录下了 FP 指标。<span style="color: black;">然则</span>此时 DOM 内容还没<span style="color: black;">起始</span>绘制,可能需要⽂件下载、解析等过程,<span style="color: black;">仅有</span>当 DOM 内容发⽣变化才会触发,⽐如说渲染出了⼀段⽂字,此时就会记录下 FCP 指标。<span style="color: black;">因此呢</span>说<span style="color: black;">咱们</span><span style="color: black;">能够</span>把这两个指标认为是和⽩屏时间<span style="color: black;">关联</span>的指标,<span style="color: black;">因此</span>肯定是最快越好。</span></p><span style="color: black;"><span style="color: black;">function</span> <span style="color: black;">getFCP</span>() </span>{
<span style="color: black;">new</span> PerformanceObserver(<span style="color: black;">(<span style="color: black;">entryList, observer</span>) =></span> {
<span style="color: black;">let</span> entries = entryList.getEntries();
<span style="color: black;">for</span> (<span style="color: black;">let</span> i = <span style="color: black;">0</span>; i < entries.length; i++) {<span style="color: black;">if</span> (entries.name === <span style="color: black;">first-contentful-paint</span>) {
<span style="color: black;">console</span>.log(<span style="color: black;">FCP</span>, entries.startTime);
}
}
}).observe({ <span style="color: black;">entryTypes</span>: [<span style="color: black;">paint</span>] });
}<h1 style="color: black; text-align: left; margin-bottom: 10px;">3.⾸⻚时间</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">当 onload 事件触发的时候,<span style="color: black;">亦</span><span style="color: black;">便是</span><span style="color: black;">全部</span>⾸⻚加载完成的时候</span></p><span style="color: black;"><span style="color: black;">function</span> <span style="color: black;">getFirstPage</span>() </span>{
<span style="color: black;">console</span>.log(
<span style="color: black;">FIRSTPAGE</span>,
performance.timing.loadEventEnd - performance.timing.fetchStart,
);
}<h1 style="color: black; text-align: left; margin-bottom: 10px;">4.最⼤内容绘制 LCP</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">⽤于记录视窗内最⼤的元素绘制的时间,该时间会随着⻚⾯渲染变化⽽变化,<span style="color: black;">由于</span>⻚⾯中的最⼤元素在渲染过程中可能会发⽣改变,<span style="color: black;">另一</span>该指标会在⽤户第⼀次交互后停⽌记录。</span></p><span style="color: black;"><span style="color: black;">function</span> <span style="color: black;">getLCP</span>() </span>{
<span style="color: black;">new</span> PerformanceObserver(<span style="color: black;">(<span style="color: black;">entryList, observer</span>) =></span> {
<span style="color: black;">let</span> entries = entryList.getEntries();
<span style="color: black;">const</span> lastEntry = entries;
<span style="color: black;">console</span>.log(<span style="color: black;">LCP</span>, lastEntry.renderTime || lastEntry.loadTime);
}).observe({<span style="color: black;">entryTypes</span>: [<span style="color: black;">largest-contentful-paint</span>] });
}
<h1 style="color: black; text-align: left; margin-bottom: 10px;">5.⾸次可交互时间 TTI</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">FCP 指标后,首个长任务执行时间点,其后无长任务或 2 个 get 请求。</span></p><span style="color: black;">从 FCP 指标后<span style="color: black;">起始</span>计算</span><span style="color: black;"><span style="color: black;">连续</span> 5 秒内⽆⻓任务(执⾏时间超过 50 ms)且⽆两个以上正在进⾏中的 GET 请求</span><span style="color: black;">往前回溯⾄ 5 秒前的最后⼀个⻓任务结束的时间</span>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/264b31aa568b4d509c4e840a9fd3fed1~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1728744254&x-signature=xVOIKIGObDwND3ppumkSpJUi%2B2c%3D" style="width: 50%; margin-bottom: 20px;"></div><span style="color: black;"><span style="color: black;">function</span> <span style="color: black;">getTTI</span><span style="color: black;">()</span></span> {
let <span style="color: black;">time</span>= performance.timing.domInteractive - performance.timing.fetchStart;
console.<span style="color: black;">log</span>(<span style="color: black;">TTI</span>, <span style="color: black;">time</span>);
}<h1 style="color: black; text-align: left; margin-bottom: 10px;">6.⾸次输⼊延迟 FID</h1><span style="color: black;">从用户<span style="color: black;">第1</span>次与页面交互到浏览器<span style="color: black;">实质</span>能够<span style="color: black;">起始</span>处理事件的时间,在 FCP(首次内容绘制) 和 TTI (首次可交互时间)之间</span><span style="color: black;">⽤户⾸次与⻚⾯交互时响应的延迟</span><span style="color: black;">eg:点击输入框后,因渲染等<span style="color: black;">导致</span>的延迟</span><span style="color: black;"><span style="color: black;">function</span> <span style="color: black;">getFID</span>() </span>{
<span style="color: black;">new</span> PerformanceObserver(<span style="color: black;">(<span style="color: black;">entryList, observer</span>) =></span> {
<span style="color: black;">let</span> firstInput = entryList.getEntries()[<span style="color: black;">0</span>];
<span style="color: black;">if</span> (firstInput) {
<span style="color: black;">const</span>FID = firstInput.processingStart - firstInput.startTime;<span style="color: black;">console</span>.log(<span style="color: black;">FID</span>, FID);
}
}).observe({ <span style="color: black;">type</span>: <span style="color: black;">first-input</span>, <span style="color: black;">buffered</span>: <span style="color: black;">true</span> });
}<h1 style="color: black; text-align: left; margin-bottom: 10px;">7.累计位移偏移 CLS</h1><span style="color: black;"><span style="color: black;">经过</span>计算未在用户输入 500 毫秒内<span style="color: black;">出现</span>的布局偏移的偏移分数总和来<span style="color: black;">测绘</span>内容的不稳定性</span><span style="color: black;">⻚⾯渲染过程中<span style="color: black;">忽然</span>插⼊⼀张巨⼤的图⽚<span style="color: black;">或</span>说点击了某个按钮<span style="color: black;">忽然</span>动态插⼊了⼀块内容等等相当影响用户体验</span><span style="color: black;">这个指标<span style="color: black;">便是</span>为这种<span style="color: black;">状况</span>⽽⽣的,计算⽅式为:</span><span style="color: black;"><span style="color: black;">位移影响的⾯积 * 位移距离</span></span><span style="color: black;">CLS <span style="color: black;">举荐</span>值为<span style="color: black;">小于</span> 0.1</span><span style="color: black;">CLS 较差的最<span style="color: black;">平常</span>原<span style="color: black;">由于</span>:</span><span style="color: black;">无尺寸的图像</span><span style="color: black;">无尺寸的<span style="color: black;">宣传</span>、嵌入和 iframe</span><span style="color: black;">动态注入的内容</span><span style="color: black;"><span style="color: black;">引起</span>不可见文本闪烁 (FOIT)/无样式文本闪烁 (FOUT) 的网络字体</span><span style="color: black;">在更新 DOM 之前等待网络响应的操作</span>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p26-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/fb04e597f54b44acbd75aa72dac601aa~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1728744254&x-signature=t6dQvQXifrifw%2FKbLwJkLE3oPFo%3D" style="width: 50%; margin-bottom: 20px;"></div><span style="color: black;"><span style="color: black;">function</span> <span style="color: black;">getCLS</span>() </span>{
<span style="color: black;">try</span> {
<span style="color: black;">let</span> cumulativeLayoutShiftScore = <span style="color: black;">0</span>;
<span style="color: black;">const</span> observer = <span style="color: black;">new</span>PerformanceObserver(<span style="color: black;">(<span style="color: black;">list</span>) =></span> {
<span style="color: black;">for</span> (<span style="color: black;">const</span> entry of list.getEntries()) {
<span style="color: black;">// Only count layout shifts without recent user input.</span>
<span style="color: black;">if</span>(!entry.hadRecentInput) {
cumulativeLayoutShiftScore += entry.value;
}
}
});
observer.observe({<span style="color: black;">type</span>: <span style="color: black;">layout-shift</span>, buffered: <span style="color: black;">true</span> });
<span style="color: black;">document</span>.addEventListener(<span style="color: black;">visibilitychange</span>, <span style="color: black;"><span style="color: black;">()</span> =></span> {
<span style="color: black;">if</span> (<span style="color: black;">document</span>.visibilityState === <span style="color: black;">hidden</span>) {
<span style="color: black;">// Force any pending records to be dispatched.</span>
observer.takeRecords();
observer.disconnect();
<span style="color: black;">console</span>.log(<span style="color: black;">CLS:</span>, cumulativeLayoutShiftScore);
}
});
} <span style="color: black;">catch</span> (e) {
<span style="color: black;">// Do nothing if the browser doesnt support this API.</span>
}
}
<h1 style="color: black; text-align: left; margin-bottom: 10px;">8.谷歌标准</h1>
<div style="color: black; text-align: left; margin-bottom: 10px;"><img src="https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/193f1e2a33b94d11a9e04bfcb8186921~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1728744254&x-signature=3d7fy%2BdxS2ckgSvtkLhynNAiSpM%3D" style="width: 50%; margin-bottom: 20px;"></div><span style="color: black;">LCP(Largest Contentful Paint - 最大内容绘制时间)=> 加载性能</span><span style="color: black;">FID(First Input Delay - 首次输入延迟)=> 交互性</span><span style="color: black;">CLS(Cumulative Layout Shift - 累计位移偏移)=> 视觉稳定性</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">9.<span style="color: black;">怎样</span><span style="color: black;">运用</span></h1><span style="color: black;">vue:定义公用<span style="color: black;">办法</span>类,common.js,mounted 阶段页面进行挂载,$nextTick()里对响应<span style="color: black;">办法</span>进行<span style="color: black;">运用</span></span><span style="color: black;">react:hooks useEffect()中<span style="color: black;">运用</span></span><span style="color: black;"><span style="color: black;">react.useEffect(() => {}, []);</span></span><span style="color: black;"><span style="color: black;">机构</span>内部<span style="color: black;">运用</span>打点系统:<span style="color: black;">运用</span> echars 绘制,<span style="color: black;">运用</span>均值统计、百分位数统计、样本分布统计输出性能</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">优化<span style="color: black;">办法</span></h1>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">1.LCP</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">影响<span style="color: black;">原因</span></span></p><span style="color: black;">缓慢的服务器响应速度</span><span style="color: black;">阻塞渲染的 JavaScript 和 CSS</span><span style="color: black;">缓慢的资源加载速度</span><span style="color: black;">客户端渲染</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">提高</span><span style="color: black;">办法</span></span></p><span style="color: black;">提⾼带宽(⽹速)</span><span style="color: black;">需要使⽤ webpack 进⾏ tree-shaking</span><span style="color: black;">使⽤路由懒加载,<span style="color: black;">仅有</span>在使⽤的时候在进⾏路由加载</span><span style="color: black;"><span style="color: black;">安排</span> CDN,缩短⽤户与节点之间的距离(⽹速)</span><span style="color: black;">建⽴缓存,提⾼下次加载速度。</span><span style="color: black;">开启 gzip 压缩。</span><span style="color: black;">不要在头部添加任何 script 标签,或<span style="color: black;">运用</span> js 异步加载 defer。</span><span style="color: black;"><span style="color: black;">针对</span>少量⼩图标(单个<span style="color: black;">尽可能</span>不要超过 10K 的),<span style="color: black;">咱们</span><span style="color: black;">能够</span>使⽤ url-loader 打包。<span style="color: black;">或</span>使⽤将图标转化为字体库,异步进⾏加载。</span><span style="color: black;"><span style="color: black;">针对</span>⼤图标的话,需要做到在展示的时候再去加载。<span style="color: black;">亦</span><span style="color: black;">便是</span>当图⽚<span style="color: black;">显现</span>到浏览器窗⼝的时候再去加载,⽽不是⾸屏的图⽚<span style="color: black;">所有</span>加载。</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">2.FID</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">影响<span style="color: black;">原因</span></span></p><span style="color: black;"><span style="color: black;">针对</span>⽤户可操作时间,影响⼀个是注册的事件<span style="color: black;">是不是</span><span style="color: black;">能够</span>被执⾏(说的通俗点<span style="color: black;">便是</span> JS 脚本<span style="color: black;">是不是</span>加载完毕),以及<span style="color: black;">是不是</span>存在</span><span style="color: black;"><span style="color: black;">⻓任务</span></span>。<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">提高</span><span style="color: black;">办法</span></span></p><span style="color: black;"><span style="color: black;">分割长任务</span></span><span style="color: black;">对⽂件进⾏</span><span style="color: black;"><span style="color: black;">懒加载</span></span>,不要⼀次性把所有的 JS 加载出来。这就需要使⽤路由懒加载,在<span style="color: black;">转</span>到某个路由的时候,再去加载他的脚本资源。<span style="color: black;">这般</span>就<span style="color: black;">能够</span><span style="color: black;">保准</span> JS 加载速度的优化。<span style="color: black;">不要在响应事件⾥有<span style="color: black;">太多</span>的运算,<span style="color: black;">引起</span>卡顿。<span style="color: black;">倘若</span>确有需要,应当开启</span><span style="color: black;"><span style="color: black;">webWorker</span></span>,新起线程运算。<h1 style="color: black; text-align: left; margin-bottom: 10px;">3.CLS</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">影响<span style="color: black;">原因</span></span></p><span style="color: black;">无尺寸的图像</span><span style="color: black;">无尺寸的<span style="color: black;">宣传</span>、嵌入和 iframe</span><span style="color: black;">动态注入的内容</span><span style="color: black;"><span style="color: black;">引起</span>不可见文本闪烁 (FOIT)/无样式文本闪烁 (FOUT) 的网络字体</span><span style="color: black;">在更新 DOM 之前等待网络响应的操作</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">提高</span><span style="color: black;">办法</span></span></p><span style="color: black;">设置<span style="color: black;">照片</span>的时候给宽高</span><span style="color: black;">预留后续动态<span style="color: black;">插进</span>的内容:骨架屏</span><span style="color: black;"><span style="color: black;">倘若</span>经常需要变动的元素,脱离⽂档流,<span style="color: black;">或</span>是占据位置,只是<span style="color: black;">隐匿</span></span><span style="color: black;">文本字体等资源预加载</span><span style="color: black;">倾向于<span style="color: black;">选取</span> transform 动画,而不是触发布局偏移的属性动画</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">实战</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">整体优化思路及解析:</span></p><span style="color: black;">从浏览器输入 url 到页面各<span style="color: black;">周期</span>做了什么,进行性能优化</span><span style="color: black;"><span style="color: black;">按照</span>前端性能指标进行优化</span><span style="color: black;">框架特有的性能优化点:小程序分包、vue 路由按需加载等</span><span style="color: black;">优化<span style="color: black;">办法</span>:<span style="color: black;">研发</span>规范、技术架构设计、系统架构设计</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">1.浏览器加载优化</h1>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">DNS 预解析、预链接</h1><span style="color: black;"><!-- 开启隐式预解析:默认<span style="color: black;">状况</span>,浏览器对a标签中与当前域名不在同一域的<span style="color: black;">关联</span>域名进行预获取且缓存结果,<span style="color: black;">针对</span>https失效 --></span>
<span style="color: black;"><<span style="color: black;">meta</span> <span style="color: black;">http-equiv</span>=<span style="color: black;">"x-dns-prefetch-control"</span> <span style="color: black;">content</span>=<span style="color: black;">"on"</span> /></span>
<span style="color: black;"><!-- 只解析域名,不进行资源下载 --></span>
<span style="color: black;"><<span style="color: black;">link</span> <span style="color: black;">rel</span>=<span style="color: black;">"dns-prefetch"</span> <span style="color: black;">href</span>=<span style="color: black;">"http://www.baidu.com"</span> /></span>
<span style="color: black;"><!-- 将会做 DNS 解析,TLS 协商和 TCP 握手 --></span>
<span style="color: black;"><<span style="color: black;">link</span> <span style="color: black;">rel</span>=<span style="color: black;">"preconnect"</span> <span style="color: black;">href</span>=<span style="color: black;">"//baidu.com"</span> /></span>
<span style="color: black;"><!-- 在浏览器空闲时下载资源 --></span>
<span style="color: black;"><<span style="color: black;">link</span> <span style="color: black;">rel</span>=<span style="color: black;">"prefetch"</span> <span style="color: black;">href</span>=<span style="color: black;">"https://css-tricks.com/a.png"</span> /></span>
<span style="color: black;"><!-- 浏览器会提前完成所有的资源加载,执行,渲染并<span style="color: black;">保留</span>在内存里 --></span>
<span style="color: black;"><<span style="color: black;">link</span> <span style="color: black;">rel</span>=<span style="color: black;">"prerender"</span> <span style="color: black;">href</span>=<span style="color: black;">"https://css-tricks.com"</span> /></span>
<span style="color: black;"><!-- 提前下载资源,影响资源加载<span style="color: black;">次序</span>,后置下载资源前置下载 --></span>
<span style="color: black;"><<span style="color: black;">link</span>
<span style="color: black;">rel</span>=<span style="color: black;">"preload"</span>
<span style="color: black;">href</span>=<span style="color: black;">"https://fonts.gstatic.com/s/sofia/v8/bjl.woff2"</span>
<span style="color: black;">as</span>=<span style="color: black;">"font"</span>
<span style="color: black;">crossorigin</span>=<span style="color: black;">"anonymous"</span>
/></span>
<span style="color: black;"><!-- ⽂件加载完成后,会执⾏此脚本,执⾏<span style="color: black;">次序</span>⽆法<span style="color: black;">保准</span>,先加载完成的先执⾏ --></span>
<span style="color: black;"><<span style="color: black;">script</span> <span style="color: black;">src</span>=<span style="color: black;">"./static/demo1.js"</span> <span style="color: black;">async</span>></span><span style="color: black;"></<span style="color: black;">script</span>></span>
<span style="color: black;"><!-- 延迟执⾏脚本,解析完</html>后执⾏,执⾏<span style="color: black;">次序</span>不变 --></span>
<span style="color: black;"><<span style="color: black;">script</span> <span style="color: black;">src</span>=<span style="color: black;">"./static/defer-demo1.js"</span> <span style="color: black;">defer</span>></span><span style="color: black;"></<span style="color: black;">script</span>></span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">更加多</span>内容见前端性能优化之 rel=“prefetch“预/懒加载功能</span></p>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">http 请求<span style="color: black;">周期</span></h1><span style="color: black;">减少 http 请求<span style="color: black;">恰当</span>利用时序:资源合并(雪碧图)、<span style="color: black;">运用</span> promise.all 并发请求</span><span style="color: black;">减少资源体积:减少 cookie 信息、<span style="color: black;">照片</span>格式优化、gzip 静态资源压缩、webpack 打包压缩</span><span style="color: black;"><span style="color: black;">恰当</span>利用缓存:cdn、http 缓存(强缓存和协商缓存)、本地缓存(localStorage、sessionStorage)</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">浏览器渲染<span style="color: black;">周期</span>:下载 css 并解析、下载 js 文件并解析会影响页面首屏渲染</h1><span style="color: black;">减少重排重绘,<span style="color: black;">尽可能</span><span style="color: black;">运用</span> css 动画,<span style="color: black;">或</span>添加 will-change 属性</span><span style="color: black;">script 脚本放在 body 元素中⻚⾯内容的后⾯,避免 JS 阻碍 html 解析,减少⽩屏时间</span><span style="color: black;">css 文件<span style="color: black;">尽可能</span>放在 head 中,尽快下载和解析</span><span style="color: black;"><span style="color: black;">运用</span>预解析和异步加载:prefetch、prerender、preload、async、defer</span><span style="color: black;">服务器端渲染 ssr</span><span style="color: black;">资源按需引入:路由懒加载,组件库按需引入</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">2.技术框架</h1><span style="color: black;">路由懒加载</span><span style="color: black;">组件按需引入:babel 插件转换</span><span style="color: black;">webpack 打包优化配置:资源压缩、资源拆分<span style="color: black;">安排</span>至 cdn(externals)</span><span style="color: black;">小程序:分包加载、setData 操作优化、限频接口调用优化等</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">3.架构优化</h1><span style="color: black;">cdn 预热</span><span style="color: black;">nginx 缓存配置、gzip 压缩开启</span><span style="color: black;">ssr 及预渲染</span><span style="color: black;">后端 bigpipe 引入:动态网页加载技术</span>
<h1 style="color: black; text-align: left; margin-bottom: 10px;">4.bigpipe 框架</h1>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">bigPipe<span style="color: black;">是由于</span> facebook 提出来的⼀种动态⽹⻚加载技术。 它将⽹⻚分解成<span style="color: black;">叫作</span>为 pagelets 的⼩块,<span style="color: black;">而后</span>分块传输到浏览器端,进⾏渲染。 它<span style="color: black;">能够</span>有效地<span style="color: black;">提高</span>⾸屏渲染时间。bigpipe 的适⽤是服务端进⾏渲染,<span style="color: black;">而后</span>将⼀块⼀块的⽂件传递给前端。</span></p>
论坛是一个舞台,让我们在这里尽情的释放自己。 感谢楼主分享,祝愿外链论坛越办越好!
页:
[1]