资源加载优化
DNS预解析
简单介绍:
DNS 的作用是将域名解析为 IP 地址,解析的过程是耗时的,转化后会做本地缓存,我们的优化的目标主要是针对用户第一次访问站点的时候陷入长时间白屏的问题。
DNS 解析可以分为两类:
第一类是页面 DNS 解析,第一次访问站点, 这个过程是省不了的
第二类是其他资源的 DNS 解析,在浏览器解析 html 的时候,会遇到一些 script 元素、link 元素,此时会暂停 html 的解析,转而加载 JS,里面就包含了 DNS 解析,这个过程是耗时的,会阻塞浏览器渲染主线程,所以该如何进行优化呢?答案是采用 DNS 预解析!
dns预解析是提前解析之后可能会用到的域名,使解析结果缓存到系统缓存中,缩短DNS解析时间,进而提高网站的访问速度,其范围包括文档的所有链接,包括图片、CSS、JS;
如何开启DNS预解析
在 HTML 的 head 部分添加以下代码来启用 DNS 预解析,href 属性指定了需要预解析的主机名
<link rel="dns-prefetch" href="//baidu.com">
ps: dns-prefetch 仅对跨域上的 DNS 查找有效,因此请避免使用它来指向相同域
HTTP 页面下所有的 a 标签的 href 都会自动去启用 DNS Prefetch,也就是说,你网页的 a 标签 href 带的域名,是不需要在 head 里面加上 link 手动设置的。
缓存
- zache离线压缩包(服务端,资源越近越好)
页面主文档、JS&CSS资源、核心图片资源添加Zcache ,(离线压缩包缓存) 告诉客户端提前加载资源 - 强缓存和协商缓存(服务端负责)
使用 CDN
通过在多台服务器部署相同的副本,当用户访问时,服务器根据用户跟哪台服务器距离近,来决定哪台服务器去响应这个请求
压缩响应
减少 HTTP 请求产生的响应包的大小, Web 客户端可以通过 HTTP 请求中的 Accept-Encoding 头来标识对压缩的支持, 如果 Web 服务器看到请求中的这个头,就会使用客户端列出的方法中的一种来压缩响应。Web 服务器通过响应中的 Content-Encoding 头来告知 Web 客户端使用哪种方法进行的压缩
图片压缩
- 压缩方法有两种,一是通过在线网站进行压缩,二是通过 webpack 插件 image-webpack-loader
- 使用 webp 格式的图片
优点:更高的压缩率,得到更小的文件,使得载速度更快,提升网页加载性能和用户体验
缺点:老旧浏览器不兼容,编码和解码速度更慢
发现带透明通道的图片或者较小的图片压缩后会更大 - 提倡小图转base64, base64可以将一张图片数据编码成一串字符串,使用该字符串代替图像地址, 减少一张图片的http请求
预加载
-
使用preload, prefetch预加载css或者图片
preload用于提前加载当前页面所需的关键资源(首页)
prefetch 用于在浏览器空闲时提前加载未来页面可能需要的资源(非首页) -
图片懒加载,滚动到相应位置才加载图片。
图片的加载是由 src 引起的,当对 src 赋值时,浏览器就会请求图片资源。将图片地址存储到data-xxx属性上, 判断图片是否在可视区域, 如果在,就设置图片src, 绑定scroll监听事件
代码逻辑优化
Css
选择器减少嵌套, 减少使用后代表达器和通配符,避免使用css 表达式会被频繁地计算。
能用css3实现的图片尽量不要用图片(cilp-path, 渐变、阴影等)
css3动画和canvas动画都比JS动画性能好
js
js可以修改CSSOM和DOM,因此js会阻塞页面的解析和渲染,并且会等待css资源的加载。给js资源添加defer或者async,延迟js脚本的执行。或者将 script 标签放在 body 标签底部的原因。(提首屏)
减少重绘重流
● display: none改为使用visibility:hidden ;
● 通过修改元素的 class/csstext,而不是直接修改样式属性,这样可以将多个样式的变化合并成一次重排和重绘。
● 使用 CSS 动画而不是通过 JavaScript 修改样式,可以利用硬件加速,提高性能, 如使用 transform:translateY 替代 position:top(top会触发回流)
● 分离读写操作, 缓存布局信息,避免重复取值:offsetLeft,scrollLeft, 为了获取最新值, 会造成浏览器强制刷新渲染队列
● 离线操作: 批量修改DOM时,可以先让元素脱离文档流,等修改完毕后,再放入文档流。(文档片段createdocumentFragment)
● 使用 requestAnimationFrame: 使用该 API 能够将重排和重绘操作集中在一次浏览器绘制之前执行,减少性能开销。
设定宽度和高度
可减少CLS(累计位移偏移), 用户体验更好. 如果没有设置,但这样做会导致浏览器在渲染页面的时候,一边下载图片一边计算大小,图片很多的时候,需要不断地调整页面,
防抖和节流
比如点击事件触发请求等, 要做好防抖节流
首屏优化手段
- 骨架屏(首屏)
- 服务端渲染(ssr)
- js放在页面底部加载
性能分析工具
- 利用webpack analayze插件分析打包情况, 是否有公共依赖包重复打包,没用的包被打包, 不同版本的包被重复打包
- preformance: 生成性能面板
- lighthouse: 性能测试工具, 生成分析报告,返回性能分数,给出性能指导方案,
webpack优化
组件库按需引入
只引入指定组件和对应的样式
elementUI 需要借助 babel-plugin-component 插件实现
gzip 压缩(比较旧)
考虑到浏览器的兼容性,Gzip 不需要在webpack进行压缩,最好用nginx配置,动态进行
tread-loader多线程打包
由于webpack 是单线程模型的,tread-loader能让webpack 同一时间处理多个任务,发挥多核 CPU 电脑的作用
Tree Shaking
可删除无用代码, 前提是模块必须采用 ES6 Module 语法,因为 Tree Shaking 依赖 ES6 的静态语法:import 和 export。不同于 ES6 Module,CommonJS 支持动态加载模块,在加载前是无法确定模块是否有被调用,所以并不支持 Tree Shaking
externals 提取项目依赖
如果有依赖是外部环境(自己的cdn,第三方cdn 不稳定)提供的,在打包时告诉 externals这些忽略它们, 缺点:直接在html内引入的,失去了按需引入的功能,只能引入组件库完整的js和css
常见的性能指标
Frist Contentful Paint(FCP): 页面上第一个元素绘制的时间点,对应白屏时间,
LCP(Largest Contentful Paint): 最大内容绘制,指页面上最大的图片或文字绘制的时间点
Time to Interactive(TTI):可流畅地响应用户交互的时间, 找到第一个连续 5s 安静窗口,从安静窗口反推,找到最后一个长任务, 这个长任务结束的时间点就是 TTI
FID(First Input Delay ): 用户首次交互时间
CLS Cumulative Layout Shift): 累计位移偏移, 越低说明页面跳来跳去的情况就越少,用户体验越好
如何减少CLS
a. 给image,video或者其他具有长宽比的元素设置长宽值;
b. 尽量不要在已经渲染的内容前面插入内容;
c. 尽量选择transform animations属性去触发布局变动;
参考文档
前端性能优化系列——DNS预解析和优化
当面试官问我前端可以做的性能优化有哪些
前端性能优化——包体积压缩82%、打包速度提升65%