0
点赞
收藏
分享

微信扫一扫

前端性能优化的整理笔记


🚴 前言

🏄利用碎片化的时间,系统的整理,性能优化的知识点。

🎯 前端性能优化,需要深入了解前端技术的原理。

💪从而,做出高性能的工程,提高自身含金量。

🏃 使用流行的性能优化技术,快速提高Web性能。

🚴了解技术背后的优秀设计思想,掌握前沿解决方案。

💎整理笔记的目的

了解性能优化的关键环节,知识储备的升级。

掌握流行且成熟的多种性能优化技术。

熟悉大厂必会,生产级别的高性能解决方案。

💎技术储备

前端技术栈,非常丰富。性能优化,需要一定的技术储备:

1.掌握 HTML,JavaScript,CSS,HTTP 基础知识

2.具备实际Web开发经验

3.最好使用过Webpack,Vue,React,Chrome DevTools 等

💎性能优化的意义

网站性能, 影响到用户参与度和用户留存,从而影响到转换率和业务收益。

第一章 性能优化指标与测量工具

重要性

性能,是Web网站和应用的支柱。

Amazon (亚马逊网上购物商城)发现:每100ms延迟,导致 1% 的销量损失。



前端性能优化的整理笔记_Powered by 金山文档


寻找性能瓶颈

  • 了解性能指标,多块才算快
  • 利用测量工具和API
  • 优化问题,重新测量,迭代

🚀 优化,是一个不断迭代的过程。

移动端挑战多

  • 设备硬件,网速,屏幕尺寸,交互方式。
  • 用户更缺少耐心,超过3秒加载导致53%的跳出率。
  • 持续增长的移动用户和移动电商业务。譬如,电商网站的搜索速度

关键词 bounce rate

跳出率是指在只访问了入口页面(例如网站首页)就离开的访问量与所产生总访问量的百分比。

跳出率计算公式:跳出率=访问一个页面后离开网站的次数/总访问次数

性能指标和优化目标

💎 打开浏览器控制台,切换至 NetWork 选项卡

可以看到各种资源的加载时间,通过 Waterfall 可以看到每个阶段的用时。

譬如,TTFB(Time To First Byte)请求发送出去,直到返回响应结果,经历了多少时间。

关键词 TTFB (Time To First Byte)

是发出页面请求到接收到应答数据第一个字节的时间总和。

它包含了DNS解析时间、 TCP连接时间、发送HTTP请求时间和获得响应消息第一个字节的时间

💎 切换至 Lighthouse 选项卡,显示网站性能分数。

其中有几个指标:

  • First Contentful Paint 从白屏到出现内容
  • Speed Index 速度指数,如果比4秒小,网站就是快的。否则,就是需要优化的。
  • 页面加载时间
  • 首次渲染

💎 切换至 Performance 选项卡

ctr + shift + p 调出指令窗口,

输入 frame

选择 Show frames per second (FPS) meter

直接通过FPS视窗,查看页面的帧数

异步请求在1秒之内,返回数据。超过1秒,前端增加加载动画。

总结:性能优化-加载,测量指标

  • Speed Index 速度指数
  • TTFB (Time To First Byte)发出页面请求之后,接收到应答数据的第一个字节,这段时间的总和。
  • 页面加载时间,页面所有资源加载完成,所用的时间。
  • 首次渲染,第一次出现内容的时间。

性能优化-交互

  • 交互动作的反馈时间,交互的反馈要及时。
  • 帧率FPS 帧率要足够高60FPS
  • 异步请求的完成时间,尽量在一秒之内完成。完成不了,加载动画。

RAIL测量模型

RAIL,以用户为核心的性能模型

谷歌从用户体验触发,制定了性能优化的标准 RAIL



前端性能优化的整理笔记_css_02


RAIL是四个英语单词的首字母缩写

1.Response 响应

网站给用户操作的响应的体验

2.Animation 动画

网站动画是否流畅。如果卡顿,需要优化

3.Idle 空闲

合理地应用浏览器空闲时间

4.Load 加载

页面加载时间是最常见的性能话题

RAIL的目标

让良好的用户体验,成为性能优化的目标

RAIL的评估标准

1.Response 响应,用户操作后 100 毫秒内要得到响应

2.Animation 动画,每一帧的渲染在 16 毫秒内完成

3.Idle 空闲,尽可能增加空闲时间

4.Load 加载,在 5 秒内完成内容加载并可以交换

性能测量工具

在优化的路上,发现问题,解决问题。性能测量工具,可以帮助我们发现问题。

  • Chome DevTools 开发调试,性能评测
  • Lighthouse 网站整体质量评估
  • WebPageTest 多测试地点,全面性能报告

💎 使用 WebPageTest 评估Web网站性能

www.webpagetest.org/

WebPageTest 提供了世界各地的服务器和各种浏览器。

解读 WebPageTest 的报告

1.waterfall chart 请求瀑布图

2.first view 首次访问

3.repeat view 二次访问

使用Lighthouse分析性能

安装 lighthouse

npm install -g lighthouse
复制代码

测试网站性能

lighthouse https://www.bilibili.com/复制代码

Lighthouse 除了分析性能,还有给出了优化建议。

使用 Chrome DevTools 分析性能

💎ctr + shift + p 调出指令窗口,

输入 block

选择 Show Network request blocking

添加过滤的js文件,过滤掉的默认不加载。

💎切换至 Network 选项卡

各种资源的大小Size 有两个,实际的大小,和网络传输的大小。

可以通过压缩js文件,减少网络传输的大小。

💎 切换至 Performance 选项卡

点击录制按钮,开始录制新内容。页面所发生的的一切,包括交互,都会被记录下来。

方便进行性能分析。

常用的性能测试API

譬如,计算可交互时间

window.addEventListener('load', function() {
  // 可交互时间let timing = performance.getEntriesByType('navigation')[0];
  // 计算let tti = timing.domInteractive - timing.fetchStart;
});
复制代码

譬如,判断页面隐藏,还是显示

let vEvent = 'visibilitychange';
if(document.webkitHidden !== undefined) {
  vEvent = 'webkitvisibilitychange';
}
document.addEventListener(vEvent, function() {
  if(document.hidden || document.webkitHidden) {
    console.log('页面隐藏');
  } else {
    console.log('页面显示');
  }
});
复制代码

譬如,监听当前网络状态

// 判断当前网络状态let connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
connection.addEventListener('change', function() {
  let type = connection.effectiveType;
  console.log('当前网络状态'+type);
});
复制代码

通过性能API可以获得关键的时间节点

DNS 解析耗时: domainLookupEnd - domainLookupStart
TCP 连接耗时: connectEnd - connectStart
SSL 安全连接耗时: connectEnd - secureConnectionStart
网络请求耗时 (TTFB): responseStart - requestStart
数据传输耗时: responseEnd - responseStart
DOM 解析耗时: domInteractive - responseEnd
资源加载耗时: loadEventStart - domContentLoadedEventEnd
FirstByte时间: responseStart - domainLookupStart
白屏时间: responseEnd - fetchStart
首次可交互时间: domInteractive - fetchStart
DOMReady 时间: domContentLoadEventEnd - fetchStart
页面完全加载时间: loadEventStart - fetchStart
http 头部大小: transferSize - encodedBodySize
重定向次数:performance.navigation.redirectCount
重定向耗时: redirectEnd - redirectStart
复制代码

第二章 渲染优化

首先,需要了解,浏览器渲染原理。

通过了解浏览器渲染,都经历了哪些步骤,才能有针对性的进行优化。

核心概念:关键渲染路径 critical rendering path

浏览器渲染,到底是一个什么样的过程?

网络资源,譬如js文件和css文件,进行解析,最终渲染到页面上。

浏览器的渲染流程

1.第一步,触发视觉变化,不局限于js,有可能是css样式的改变,animation等等

2.第二步,浏览器对样式重新进行计算,计算哪些元素的css改变

3.第三步,布局,把元素绘制到页面上,需要知道元素的大小和位置,几何信息。

4.第四步,绘制,把元素画到页面上,包括文字,图片,颜色,阴影,等等

5.第五步,合成,浏览器把不同的东西画在不同的层上,然后合成到一起

当浏览器拿到服务器返回的资源之后,它都做了些什么?

💎 浏览器构建对象模型

构建DOM对象 文档对象模型

HTML => DOM

💎 构建CSSOM对象

CSS => CSSOM

💎 浏览器构造渲染树

DOM CSSOM=》 Render Tree

💎 布局和绘制

关键渲染路径中,最重要的两个步骤,也是开销最高的步骤。

减少布局和绘制的发生,可以有效地提高性能。

💎 渲染树,只包含网页需要的节点

布局计算每个节点精确的位置和大小 - “盒模型”

绘制是像素化每个节点的过程

哪些操作,会导致布局更改,从而造成所谓的回流 reflow

  • 添加删除元素
  • 操作styles
  • display:none
  • offsetLeft,scrollTop,clientWidth
  • 移动元素位置
  • 修改浏览器大小,字体大小

核心,就是位置和大小的改变。

避免 layout thrashing (布局抖动)

连续不断的布局回流,很容易造成页面抖动,卡顿。

💎 1.避免回流

采用css3动画 translate 属性

积攒一些之后,统一计算

💎 2.读写分离

读的操作,进行完,再批量的进行写的操作

读,读取布局信息。

写,修改样式。

使用 FastDom 批量对DOM的读写操作

FastDom通过接收读写操作,并在下一帧捆绑它们(先读后写),从而消除DOM的相互影响。 这意味着我们能独立编写应用程序组件,而不用担心它们在应用程序中互相影响

🚀github地址

🚀示例地址

measure 读的操作,mutate 写的操作

fastdom.measure(() => {
    console.log('measure');
    fastdom.mutate(() => {
      console.log('mutate');
    });
});
复制代码

输入

fastdom.measure(() => {
  console.log('measure');
});

fastdom.mutate(() => {
  console.log('mutate');
});

fastdom.measure(() => {
  console.log('measure');
});

fastdom.mutate(() => {
  console.log('mutate');
});
复制代码

输出

measure
measure
mutate
mutate
复制代码

复合线程与图层

将页面拆分图层,进行绘制再进行复合。修改一个图层的东西,不影响其他图层。

利用 DevTools 可以了解网页的图层拆分情况。

减少重绘

利用 DevTools 识别 paint 的瓶颈

使用动画的时候,尽量使用transform

利用 will-change 创建新的图层

高频事件处理函数 防抖

let ticking = false;

if(ticking)return;
window.requestAnimationFrame(()=>{
  callback()
  ticking = false;
})
复制代码

第三章 代码优化

JavaScript的开销和如何缩短解析时间

开销在哪里?

加载,解析编译,执行。

解决方案:

Code splitting 代码拆分,按需加载

Tree shaking 代码减重

减少主线程工作量:

避免长任务

避免超过1kb的行间脚本

使用 rAF 和 rIC 进行时间调度

V8 浏览器引擎,已经做了一些优化

抽象语法树

编译过程会进行优化

运行时可能发生优化

了解V8优化机制,开发中运用这种思想

V8优化机制

1.脚本流

下载过程中,超过30kb时,单独开一个线程进行解析。最后,合并所有解析完的内容。

2.字节码缓存

重复使用的片段,缓存起来,就不再需要翻译的过程

3.懒解析

需要用到时,再进行解析

利用 Optimize.js 优化初次加载时间

🚀github地址

对象优化

💎 1.以相同顺序初始化对象成员,避免隐藏类的调整

classRectArea t {// HCOconstructor(l, w){
         this.l = l; // HC1this.w = w;// HC2
    }
}
const rect1 = newRectArea(3,4)
const rect2 = newRectArea(5,6)
复制代码

💎 2.实例化后避免添加新属性

//尽可能避免这种写法// In-object 属性const object = {color:'red'} 
// Normal/Fast 属性,存储 property store 里,需要通过描述数组间接查找产生
object.num = 1复制代码

💎 3.尽量使用Array代替 array-like 对象

//不推荐这种写法Array.prototype.forEach.call(arrObj, (value, index) => { 
    // 不如在真实数组上效率高console.log(value)
})
复制代码

💎 V8 官方建议,将类数组对象,转换为真实数组,然后进行遍历。这样操作,效率更高。

const arr = Array.prototype.slice.call(arrObj, 0); 
arr.forEach((value, index) => { 
    console.log(value)
})
复制代码

数组优化

💎 1.避免读取超过数组的长度

在 JavaScript 中除了基础数据类型,都是对象,包括数组也是对象。

如果,数组越界,undefined 会沿着原型链进行查找。

💎 2.避免元素类型转换

元素类型越具体,编译器能做的优化就越多

// 这样操作,会影响编译器的效率const array = [3,2,1]; // PACKED SMI_ELEMENTS
array.push(4.4);//PACKED DOUBLE ELEMENTS复制代码

HTML优化

HTML 优化空间比较小。优化点在于,清除没有用的空间,和可以省略的元素。

1.减小 iframe 使用

额外添加的文档,需要加载的过程,会影响父文档的加载。

而且,使用iframe开销更高。

//使用这种写法,父文档加载后,再给iframe设置src加载资源
<iframe id='a'></iframe>
document.getElementById( 'a' ).setAttribute( 'src','url');
复制代码

2.压缩空白符 打包时,压缩空白符

3.避免节点深层级嵌套 生成抽象语法树,嵌套的越深,遍历越慢

4.避免table布局 使用不灵活,开销更大

5.删除注释,减少体积

6.CSS 和 JavaScript 尽量外链

7.删除元素默认属性

借助工具 html-minifier html压缩工具

🚀github地址

npm install html-minifier
复制代码

var minify = require('html-minifier').minify;
var result = minify('<p title="blah" id="moo">foo</p>', {
  removeAttributeQuotes: true
});
result; // '<p title=blah id=moo>foo</p>'复制代码

CSS对性能的影响

1.降低CSS对渲染的阻塞

尽早的完成下载,譬如优先完成首屏的样式加载

2.利用GPU进行完成动画

对 transform 和 opacity 这样的属性,进行优化,单独建立一个层。不进行布局和重绘。

3.使用 contain 属性

contain 属性,大大降低了布局的时间。浏览器不会重新计算,同级其他元素。

.news li {
    contain: layout;
}
复制代码

4.使用font-display属性

font-display属性在@font-face声明时使用。

借助它,我们可以通过一行简单的CSS来控制字体的显示方式,而不需要使用基于JavaScript的解决方案。这意味着我们的网页可以减小体积,提高性能。

以Vue项目举例,代码优化

1.代码模块化

封装组件,代码复用。通过css预加载处理器,定义css变量和混入mixin。

2.for循环设置key值

for循环,数据遍历渲染的时候,每一项设置唯一的值。

为了让Vue内部核心代码能更快地找到该条数据,当旧值和新值取对比的时候,可以更快的定位到diff

3.Vue路由懒加载

当首屏渲染的时候,能够加快渲染速度。

4.更加理解Vue的生命周期

不要造成内存泄漏,使用过后的全局变量在组件销毁后重新置为null

5.可以使用keep-alive

keep-alive是Vue提供的一个比较抽象的组件,用来对组件进行缓存,从而节省性能。

第四章 资源优化

资源的压缩和合并

一直以来,资源的压缩和合并,都是最为有效的优化方案。

1.减少http请求数量

2.减少请求资源的大小

HMTL压缩

1.使用在线工具进行压缩

html-minifier.bchrt.com/

2.使用 html-minifier 等npm工具

github.com/kangax/html…

CSS压缩

1.使用在线工具进行压缩

css-minifier.bchrt.com/

2.使用 clean-css 等 npm 工具

github.com/clean-css/c…

JS压缩与混淆

1.使用在线工具进行压缩

2.使用Webpack对JS在构建时压缩

CSS JS 文件合并

1.若干小文件。这种情况,可以采用

2.无冲突,服务相同的模块。这种情况, 优先考虑

3.优化加载。这种情况,不考虑

图片优化的方案

图片格式的比较

💎 JPG格式:压缩比高,画质可以很好的保存,色彩感好

使用场景,譬如首页轮播图

缺陷:边缘粗糙,logo一般不会使用 JPG

💎 PNG格式:体积比较大,一般用来做图标和logo

github.com/imagemin/im…

💎 WebP 谷歌提出的新的图片格式

JPG一样的质量,压缩比更高

图片加载的优化

💎 图片的懒加载

1.原生的图片懒加载方案

<img src="./example.jpg" loading="lazy" alt="zhangxinxu">
复制代码

2.第三方图片懒加载方案

💎使用渐进式图片

渐进式图片的解决方案

💎 使用响应式图片

srset 属性,设置多个图片源,根据屏幕宽度,挑选合适的图片

sizes 属性,视窗宽度的百分比

根据设备的 dpi 和视窗大小,显示合适的图片

字体优化

字体未下载完成时,浏览器隐藏或自动降级,导致字体闪烁

使用 font-display 属性

第五章 构建优化

项目构建的时候,通过配置,进行优化。

  • webpack的优化配置
  • 代码拆分
  • 代码压缩
  • 持久化缓存
  • 监测与分析
  • 按需加载

这次不展开讲,先挖个坑。

第六章 传输加载优化

在 nginx上 配置 Gzip 压缩

对传输资源,进行体积压缩,可高达 90%

如何配置 nginx 启用 Gzip

gzip  on;
gzip_min_length 1k;
gzip_buffers 16 64k;
gzip_http_version 1.1;
gzip_comp_level 9;
gzip_types text /plain  application /x-javascript  text /css  application /xml ;
gzip_vary on;
复制代码

启用Keep Alive

Keep Alive是在TCP中一个可以检测死连接的机制,可以保持tcp长连接不被断开,属于 tcp 层功能。

HTTP1.1协议默认开启 keepa-live 保持长连接,主要作用是:

提高对 tcp 连接的复用率,减少创建连接过程给系统带来的性能损耗。

HTTP标准中的一部分,默认是开启的。

相关参数的配置,到达最优的体验。

Request Headers 请求头中 Connection: keep-alive 表示开启了 Keep Alive

HTTP资源缓存



前端性能优化的整理笔记_加载_03


官方文档 developer.mozilla.org/zh-CN/docs/…

Service Worker实现渐进式应用

Service Worker作用

1.加速重复访问

2.离线支持

使用 service-worker 可以缓存静态文件



前端性能优化的整理笔记_Powered by 金山文档_04


Service Worker注意

1.延长了首屏时间,但页面总加载时间减少

2.兼容性

service worker 在浏览器和移动端的兼容性如下图所示:



前端性能优化的整理笔记_加载_05


3.只能在localhost或https下使用

HTTP/2加速传输

HTTP/2优势

1.二进制传输

HTTP/1是基于文本的,效率比较低,而且不安全

HTTP/2二进制编码,安全而且提供了传输效率

2.请求响应,多路复用

简而言之:多个http请求可以共用同一个TCP连接。



前端性能优化的整理笔记_css_06


3.Server push 服务端主动推送

html 页面包含 script.js 和 style.css 资源文件。客户端只需要请求page.html,

服务端发现html页面中包含资源文件,会主动推送给客户端。减少客户端请求的次数。

nginx开启HTTP2支持

listen       443 ssl http2;
server_name  www.orzr3.com;
复制代码

搭建HTTP/2服务

1.HTTP/2只能工作在HTTPS下

需要创建签名证书

2.适合较高的请求量,比较高的请求量,才能发挥他最大的作用

SSR加速渲染

SSR:server side render

服务端渲染SSR的好处

服务器把需要的组件或页面渲染成 HTML 字符串,

然后把它返回给客户端。客户端拿到手的,是可以直接渲染然后呈现给用户的 HTML 内容

1.加速首屏加载

2.改善SEO 搜索引擎优化

是否使用SSR?

1.架构大型项目,动态页面,面向公众用户

2.搜索引擎排名很重要

第七章 其他的解决方案

IconFont

通过 iconfont 字体引入图标

阿里矢量图库

www.iconfont.cn/

从 PNG 到 iconfont 的优点:

1.多个图标 =》 一套字体,减少获取时的请求数量和体积。

2.矢量图形,可伸缩

3.直接通过 CSS 修改样式(颜色,大小等)

缺点:

单色彩

SVG 解决方案

从 IconFont 到 SVG 的优点:

1.保持了图片能力,支持多色彩

2.独立的矢量图形,不像iconfont需要下载整套字体

3.XML语法

使用 FlexBox 优化布局

display: flex;
flex-flow: row wrap;
复制代码

页面渲染 rendering 和 painting 节省了不少时间,性能明显提升。

FlexBox 的优势

1.更高性能的实现方案

2.容器有能力决定子元素的大小,顺序,对齐,间隔等。

3.双向布局,横向 row 和纵向 column

预加载

优化资源加载的顺序

资源优先级

1.浏览器默认安排,资源加载优先级

先有 html 解析头部,加载js和样式,然后解析图片等资源。

2.使用 preload 和 prefetch 调整优先级

preload 优先加载

举例,通过 link 标签,可以预加载图片

<head>
    <metacharset="UTF-8"><title>Water</title><linkrel="preload"href="img/product2.svg"as="image" /></head>复制代码

prefetch 空闲加载,后面会用到的东西。

<link rel="prefetch"as="style" href="product-font.css />
复制代码

preload 和 prefetch 使用场景

1.preload 提前加载较晚出现,但是对当前页面非常重要的资源,譬如图片和字体。

2.prefetch 加载完当前页面之后,提前加载后面路由需要的资源,优先级低。

预渲染

预渲染的作用

1.大型单页应用的性能瓶颈:JS下载+解析+执行

2.SSR的主要问题:牺牲TTFB 请求过程,来补救首次加载 First Paint 实现起来,也很复杂

3.Pre-rendering 打包时提前渲染页面,没有服务端参与

vue 预渲染

npm install prerender-spa-plugin -D  
复制代码

配置 vue.config.js 和 修改main.js

修改 vue.config.js

const path = require('path')
// 预渲染插件constPrerenderSPAPlugin = require('prerender-spa-plugin')
constRenderer = PrerenderSPAPlugin.PuppeteerRenderermodule.exports = {
    configureWebpack: {
        plugins: [
            newPrerenderSPAPlugin({
                // 生成文件的路径,与webpack打包一致即可staticDir: path.join(__dirname, 'dist'),
                // 需要预渲染的路由routes: ['/', '/mine'],
                renderer: newRenderer({
                    inject: {
                        foo: 'bar'
                    },
                    headless: false,
                    renderAfterDocumentEvent: 'render-event',
                })
            })
        ]
    }
}
复制代码

修改 main.js

newVue({
    router,
    mounted() {
        document.dispatchEvent(newEvent('render-event'))
    },
    render: h =>h(App)
}).$mount('#app')
复制代码

修改路由模式为history

构建成功后 dist 目录下:

根路径和需要预渲染的路径,都生成了 index.html 文件。

当浏览器访问这时,服务器返回的就是对应 html 文件的内容。

骨架组件

使用骨架组件,减少布局移动(Layout Shift)

1.占位

2.提升用户感知性能


举报

相关推荐

0 条评论