性能优化
2020-05-27 16:56:38 36 举报
AI智能生成
性能优化
作者其他创作
大纲/内容
网络层面
优化方向
减少请求次数(资源合并)
减少单次请求所花费的时间(资源压缩)
HTTP请求过程优化
构建工具性能调优 (Webpack)
优化瓶颈
webpack 的构建过程太花时间
webpack 打包的结果体积太大
优化方案
构建过程提速策略
不要让 loader 做太多事情 (以babel-loader为例)
用 include 或 exclude 来帮我们避免不必要的转译
开启缓存 loader: 'babel-loader?cacheDirectory=true'
不要放过第三方库 (以node_modules为例)
DllPlugin插件会把第三方库单独打包到一个文件中,这个文件就是一个单纯的依赖库
将 loader 由单进程转为多进程 (Happypack)
Happypack 会充分释放 CPU 在多核并发方面的优势, 帮我们把任务分解给多个子进程去并发执行,大大提升打包效率
构建结果体积压缩
文件结构可视化,找出导致体积过大的原因
包组成可视化工具—webpack-bundle-analyzer 以插件的形式引入
拆分资源
删除冗余代码
Tree-Shaking:针对性很强,适合用来处理模块级别的冗余代码
UglifyJsPlugin: JS 或 CSS 的压缩或分离过程,将粒度更细的冗余代码去除
按需加载
图片优化
前置知识
计算机中,像素用二进制数来表示
一个像素,二进制位数越多,颜色种类越多,成像效果越细腻,文件体积越大
图片选型
JPEG/JPG
优点:有损压缩
缺陷:不支持透明度处理;处理矢量图形和 Logo 等线条感较强、颜色对比强烈的图像时,人为压缩导致图片模糊
使用场景:大的背景图、轮播图或 Banner 图
PNG
优点:无损压缩;高保真;支持透明处理
缺陷:体积太大
使用场景:小的 Logo、颜色简单且对比强烈的图片或背景;透明格式图片
SVG
优点:文件体积更小,可压缩性更强;图片可无限放大而不失真(SVG 对图像的处理不是基于像素点,而是是基于对图像的形状描述)
应用场景:SVG 是文本文件,可以像写代码一样定义 SVG,把它写在 HTML 里、成为 DOM 的一部分
Base64
文本文件、依赖编码
应用场景:非常小的 Logo;雪碧图
CDN内容分发网络
核心
缓存 —— 把资源 copy 一份到 CDN 服务器
回源 —— CDN 向它的上层服务器去要资源的过程
内容
CDN 往往被用来存放静态资源,静态资源本身具有访问频率高、承接流量大的特点,而CDN 是静态资源提速的重要手段
细节
把静态资源和主页面置于不同的域名下,完美地避免了不必要的 Cookie 的出现(因为同一个域名下的请求会不分青红皂白地携带 Cookie)
减少网络请求次数
缓存机制
HTTP缓存
强缓存 (优先级较高)
特征:利用 http 头中的 Expires 和 Cache-Control 两个字段来控制, 若命中则直接从缓存中获取资源,不会再与服务端发生通信。
实现
expires:存放过期时间戳,需要和本地时间对比,对“本地时间”有依赖(局限性)
Cache-Control(HTTP 1):expires 的完全替代方案,通过max-age存放相对时间,比expires 更加准确,它的优先级也更高
Cache-Control 应用分析
cache-control: max-age=3600, s-maxage=31536000 s-maxage仅在代理服务器中生效,客户端中我们只考虑max-age
public:既可以被浏览器缓存,也可以被代理服务器缓存 private:只能被浏览器缓存
no-cache:绕开了浏览器,直接向服务端去确认该资源是否过期 no-store:不使用任何缓存策略
协商缓存
特征
浏览器与服务器合作之下的缓存策略
浏览器需向服务器询问缓存的相关信息,判断是重新发起请求,还是从本地获取缓存的资源
如果服务端提示缓存资源未改动(Not Modified),资源会被重定向到浏览器缓存,网络请求对应状态码是 304
实现
Last-Modified
上次修改时间的时间戳,请求时携带此字段,以便服务器进行对比,进而决定是重新返回响应还是重定向
缺陷:特殊情况下服务器无法正确感知文件的变化,所以Etag出现了
Etag
每个资源根据文件内容编码生成的唯一的标识字符串
Etag 在感知文件变化上比 Last-Modified 更加准确,优先级也更高
MemoryCache 存在内存中的缓存
优先级上来说,它是浏览器最先尝试去命中的一种缓存。 从效率上来说,它是响应速度最快的一种缓存。
内存资源有限,资源存不存内存,浏览器秉承的是“节约原则”(小文件,base64通常可能被存入内存)
Service Worker Cache
一种独立于主线程之外的 Javascript 线程
可以帮我们实现离线缓存、消息推送和网络代理等功能
Push Cache
指 HTTP2 在 server push 阶段存在的缓存
本地存储
Cookie
源起:HTTP 是一个无状态协议,在服务器需要验证客户端状态的情况下,就需要用到cookie在两端通信时携带状态传输
格式:键值对
缺陷
体积有限,最大4KB,只能存储少量信息
过量的 Cookie 会带来巨大的性能浪费,同一个域名下的所有请求,都会携带 Cookie 也就是说在不需要cookie的时候,它也会随着请求跑来跑去
Web Storage
源起:为了弥补 Cookie 的局限性,让“专业的人做专业的事情”
特性
存储容量大: Web Storage 根据浏览器的不同,存储容量可以达到 5-10M 之间
仅位于浏览器端,不与服务端发生通信
分类
Local Storage
过期时间:持久化的本地存储,永远不会过期
作用域:同源策略
应用场景:理论上 Cookie 无法胜任的,都可以用Local Storage 有时我们更倾向于用它来存储一些内容稳定的资源,比如静态资源、图片等
Session Storage
过期时间:临时性的会话级别本地存储,当会话结束(页面被关闭)时,存储内容也随之被释放。
作用域:同源策略 + 在同一个浏览器窗口中打开
应用场景:存储生命周期和它同步的会话级别的信息
核心API
setItem( )、getItem( )、removeItem( )、clear( )
IndexedDB
源起:为了存储大规模的、结构复杂的数据
特性
运行在浏览器上的非关系型数据库
渲染层面
服务端渲染SSR
本质
本该浏览器做的事情,分担给服务器去做
是什么
服务端渲染:服务端组织页面,客户端拿到手的是可以直接渲染然后呈现给用户的 HTML 内容。 "页面上呈现的内容,我们在 html 源文件里也能找到。"
客户端渲染:服务端把渲染需要的静态文件发送给客户端,客户端执行相应js,渲染生成相应的 DOM,客户端渲染的源代码总是特别简洁。 "页面上呈现的内容,你在 html 源文件里里找不到"
意义
有利于SEO::服务器给到客户端的是现成的网页
首屏加载速度过慢:服务器给到客户端的是一个直接可以拿来呈现给用户的网页
应用场景
浏览器众多, 服务器稀少,所以一般情况下优先使用低成本“大招”来优化性能,最后再考虑服务端渲染
浏览器运行机制
内核
JS引擎
渲染引擎
HTML 解释器、CSS 解释器、图层布局计算、网络、存储、图形、音视频、图片解码器等等零部件
渲染模块
HTML 解释器:将 HTML 文档经过词法分析输出 DOM 树
CSS 解释器:解析 CSS 文档, 生成样式规则
图层布局计算模块:布局计算每个对象的精确位置和大小
视图绘制模块:进行具体节点的图像绘制,将像素渲染到屏幕上
JavaScript 引擎:编译执行 Javascript 代码
渲染过程
解析 HTML ——> 计算样式 ——> 计算图层布局 ——> 绘制图层 ——> 整合图层,得到页面
相关“树”
DOM 树
解析 HTML 以创建的是 DOM 树
CSSOM 树
解析 CSS创建的是 CSSOM 树(与解析DOM树并行)
渲染树
CSSOM 与 DOM 结合,得到渲染树 Render tree
布局渲染树
计算每个节点应该出现在屏幕上的精确坐标,得到布局渲染树
绘制渲染树
遍历渲染树,每个节点将使用 UI 后端层来绘制,得到绘制渲染树
基于渲染的优化
CSS 优化
避免使用通配符,只对需要用到的元素进行选择
关注可以通过继承实现的属性,避免重复定义
少用标签选择器
不要画蛇添足,.myList#title
减少嵌套
减少阻塞
CSS 阻塞
CSS 是阻塞渲染的资源,需要将它尽早(CSS放置页面首部)、尽快(CDN)地下载到客户端
JS 阻塞
JS 对 DOM 和 CSSDOM 进行修改,会阻塞 DOM
本质
JS 引擎抢走了渲染引擎的控制权,JS 引擎运行完毕之后又把控制权还给渲染引擎,继续渲染
加载方式
正常模式
这种情况下 JS 会阻塞浏览器
async 模式
异步加载,不会阻塞
defer 模式
异步加载,不会阻塞,执行推迟(整个文档解析完成后)
DOM 优化
减少 DOM 操作:JS 层面的事情,JS 自己去处理,处理好了,再来操作 DOM
异步更新
是什么
更新数据时不会立即执行,会等一个时机批量触发,可以帮助我们避免过度渲染
优越性
只看结果,不需要为过程买单,举例:更改同一个dom内容三次,异步更新只会更新最后一次
Event Loop
分类
macro(宏任务)队列
比如:setTimeout、setInterval、 setImmediate、script(整体代码)、 I/O 操作、UI 渲染等
micro(微任务)队列
比如: process.nextTick、Promise、MutationObserver 等
回流和重绘
重绘
是什么
DOM 的修改只是导致了样式的变化,并未改变几何属性,浏览器只需要绘制新的样式即可
触发情况
修改元素背景、颜色等操作
回流(重排)
是什么
DOM 的修改引发了 DOM 几何尺寸的变化,浏览器需要重新计算元素的几何属性
触发情况
改变 DOM 元素的几何属性
改变 DOM 树的结构
获取一些特定属性的值(比如offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop......clientTop...... ) 这些值需要通过即时计算得到。因此浏览器为了获取这些值,也会进行回流
两者关系
重绘不一定导致回流,回流一定会导致重绘
如何规避
将改变缓存起来,避免频繁触发回流
避免逐条改变样式,使用类名去合并样式
让 DOM 消失,执行操作之后,再展示(适用于对dom执行很多操作的情况下)
机智的浏览器
浏览器将DOM操作缓存一个 flush 队列,存放回流与重绘任务
等到任务多 or 到了一定的时间间隔 or 特殊情况下,执行出队
这是机智的Chrome,并不代表其他浏览器智商也一样,所以还是尽量手动规避
应用层面
懒加载
是什么
在图片量大的一些网站,只把首屏呈现给用户,等滚动触发的时候再去加载剩余部分,分批加载,降低性能损耗
怎么做
预置img标签,设置大小占位 <img class="pic" alt="加载中" data-src="./images/ png">
监听滚动事件
计算可视区域的高度 window.innerHeight || document.documentElement.clientHeight
元素距离可视区域顶部的高度 imgs[i].getBoundingClientRect().top
比较1和2的差值,1>2时,给元素写入真实的src,渲染图片
优化
对滚动事件进行节流处理
节流(throttle) 防抖(debounce)
节流
中心思想
在某段时间内,不管触发了多少次回调,我都只认第一次。 第一次触发后开始计时,并在计时结束时给予响应。
防抖
中心思想
在某段时间内,不管触发了多少次回调,我都只认最后一次。 只要有触发,计时器就清零重新开始,直到某一段时间内不再有触发
浏览器Performance分析
0 条评论
下一页