前端性能优化 港控/mmm° 2022-09-07 09:59 89阅读 0赞 ### 文章目录 ### * 1.图片优化 * * 1.1 图片懒加载 * 1.2 图片预加载 * 1.3 响应式图片加载 * 1.4 渐进式图片 * 1.5 图片压缩 * * 1.5.1 工具压缩 * 1.5.2 webpack 压缩 * 1.6 使用雪碧图 * * 1.6.1 webpack 合成雪碧图 * 1.7 使用 iconfont * 1.8 使用 base64 格式 * 1.9 图片格式 * * 1.9.1 JPEG * 1.9.2 PNG * 1.9.3 GIF * 1.9.4 WebP * 1.10 使用 CDN 图片 * 2. HTTP请求优化 * * 2.1 减少HTTP请求次数 * 2.2 使用 HTTP2 * 2.3 使用服务端渲染 * 3. 减少重绘重排 * * 3.1 浏览器渲染过程 * 3.2 重绘重排 * 4. 使用事件委托 # 1.图片优化 # 1. 选择`合适的图片格式`和`压缩大图`,可从根源上截图大图加载过慢的问题。 2. 使用`雪碧图`,`iconfont`,`base64`,`css 代替图片`等可减少图片 http 请求,提高页面加载速度。 3. 使用 `CDN 图片`可达到分流的效果,减少服务券压力。 4. `图片懒加载`,`预加载`,`渐进式图片`等可不同程度减少白屏时间,提高产品体验。 ## 1.1 图片懒加载 ## * 减少资源的加载,页面启动只加载首屏的图片,这样能明显减少了服务器的压力和流量,也能够减小浏览器的负担。 * 防止并发加载的资源过多而阻塞 js 的加载,影响整个网站的启动,影响用户体验 * 浪费用户的流量,有些用户并不想全部看完,全部加载会耗费大量流量。 原理:`图片懒加载`的原理就是暂时不设置图片的 src 属性,而是将图片的 url 隐藏起来(比如先写在 data-src 里面),等当前图片是否到了可视区域再将图片真实的 url 放进 src 属性里面,从而实现图片的延迟加载。 function lazyload() { let viewHeight = document.body.clientHeight //获取可视区高度 let imgs = document.querySelectorAll('img[data-src]') imgs.forEach((item, index) => { if (item.dataset.src === '') return // 用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置 let rect = item.getBoundingClientRect() if (rect.bottom >= 0 && rect.top < viewHeight) { item.src = item.dataset.src item.removeAttribute('data-src') } }) } // 可以使用节流优化一下 window.addEventListener('scroll', lazyload) 通过上面例子的实现,我们要实现懒加载都需要去监听 `scroll` 事件,使用`IntersectionObserver`可以不需要频繁地调用`scroll` 事件 `IntersectionObserver`接口 (从属于Intersection Observer API) 提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。 const imgs = document.querySelectorAll('img[data-src]') const config = { rootMargin: '0px', threshold: 0, } let observer = new IntersectionObserver((entries, self) => { entries.forEach((entry) => { if (entry.isIntersecting) { let img = entry.target let src = img.dataset.src if (src) { img.src = src img.removeAttribute('data-src') } // 解除观察 self.unobserve(entry.target) } }) }, config) imgs.forEach((image) => { // 开始简体一个元素 observer.observe(image) }) ## 1.2 图片预加载 ## `图片预加载`,是指在一些需要展示大量图片的网站,将图片提前加载到本地缓存中,从而提升用户体验。 常用的方式有两种: 1. 隐藏在 `css` 的 `background` 的 `url` 属性里面, function preloader() { if (document.getElementById) { document.getElementById('preload-01').style.background = 'url(http://domain.tld/image-01.png) no-repeat -9999px -9999px' document.getElementById('preload-02').style.background = 'url(http://domain.tld/image-02.png) no-repeat -9999px -9999px' document.getElementById('preload-03').style.background = 'url(http://domain.tld/image-03.png) no-repeat -9999px -9999px' } } function addLoadEvent(func) { var oldonload = window.onload if (typeof window.onload != 'function') { window.onload = func } else { window.onload = function () { if (oldonload) { oldonload() } func() } } } addLoadEvent(preloader) 2. 通过 `javascript` 的 `Image` 对象设置实例对象的 `src` 属性实现图片的预加载。 function preloader() { if (document.images) { var img1 = new Image() var img2 = new Image() var img3 = new Image() img1.src = 'http://domain.tld/path/to/image-001.gif' img2.src = 'http://domain.tld/path/to/image-002.gif' img3.src = 'http://domain.tld/path/to/image-003.gif' } } function addLoadEvent(func) { var oldonload = window.onload if (typeof window.onload != 'function') { window.onload = func } else { window.onload = function () { if (oldonload) { oldonload() } func() } } } addLoadEvent(preloader) ## 1.3 响应式图片加载 ## * 在不同分辨率的设备上显示不同尺寸的图片,避免资源的浪费 * 常用的方法就是 `css3` 的`媒体查询`(media query)。 @media screen and (min-width: 1200px) { img { background-image: url('1.png'); } } @media screen and (min-width: 992px) { img { background-image: url('2.png'); } } @media screen and (min-width: 768px) { img { background-image: url('3.png'); } } @media screen and (min-width: 480px) { img { background-image: url('4.png'); } } * 此外,还可以使用 `HTML5` 的 `picture` 属性进行响应式处理。方法如下: <picture> <source srcset="src/img/l.png" media="(min-width: 1200px)" /> <source srcset="src/img/2.png" media="(min-width: 992px)" /> <source srcset="src/img/4.png" media="(min-width: 768px)" /> <img src="src/img/4.png" /> </picture> ## 1.4 渐进式图片 ## * `渐进式图片`的意思是在高画质图像加载完之前会先显示低画质版本。 * 低画质版本由于画质低、压缩率高,尺寸很小,加载很快。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZtazEwMjM_size_16_color_FFFFFF_t_70] ## 1.5 图片压缩 ## * **有损压缩**:有损压缩指在压缩文件大小的过程中,损失了一部分图片的信息,也即降低了图片的质量。例如 `jpg` 格式的图片使用的就是有损压缩。 * **无损压缩**:无损压缩指的是在压缩图片的过程中,图片的质量没有任何损耗。例如 `png`、`gif` 使用的就是无损压缩。 ### 1.5.1 工具压缩 ### * [tinypng][] 免费、批量、速度块 * [智图压缩][Link 1] 百度很难搜到官网了,免费、批量、好用 * [squoosh][] 在线图片压缩工具 * [compressor][] 支持 JPG、PNG、SVG、GIF ### 1.5.2 webpack 压缩 ### 工程化的项目可以在 `webpack` 里面配置 `image-webpack-loader` 进行图片压缩 1.安装依赖 `npm install --save-dev image-webpack-loader` 2.配置 `webpack` module.exports = { ... module: { rules: [ { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use: [ { loader: 'file-loader', options: { name: '[name].[hash:7].[ext]' }, }, { loader: 'image-webpack-loader', options: { mozjpeg: { progressive: true, quality: 50, }, optipng: { enabled: true, }, pngquant: { quality: [0.5, 0.65], speed: 4, }, gifsicle: { interlaced: false, }, webp: { // 不支持WEBP就不要写这一项 quality: 75 }, }, }, ], }, ], }, } ## 1.6 使用雪碧图 ## * `雪碧图`(CSS Sprites),是一种 CSS 图像合成技术,主要用于小图片显示。 * 把 10 个小图片合并为一张大图片的画,那么只用一次请求即可拉取下来 10 个小图片的资源。 * 减少服务器压力,减少并发,减少请求次数。 * 把诸多小图片合成一张大图,利用 `backround-position` 属性值来确定图片呈现的位置 ### 1.6.1 webpack 合成雪碧图 ### 在 webpack 中,有相应的插件提供了自动合成雪碧图的功能并且可以自动生成对应的样式文件— `webpack-spritesmith`,使用方法如下 var path = require('path') var SpritesmithPlugin = require('webpack-spritesmith') module.exports = { // ... plugins: [ new SpritesmithPlugin({ src: { cwd: path.resolve(__dirname, 'src/ico'), glob: '*.png', }, target: { image: path.resolve(__dirname, 'src/spritesmith-generated/sprite.png'), css: path.resolve(__dirname, 'src/spritesmith-generated/sprite.style'), }, apiOptions: { cssImageRef: '~sprite.png', }, }), ], } 通过上面配置就能将 src/ico 目录下的所有 png 文件合成雪碧图,并且输出到对应目录 ## 1.7 使用 iconfont ## `iconfont`(字体图标),即通过字体的方式展示图标,多用于渲染图标、简单图形、特殊字体等。 优点: * 像使用字体一样,设置大小、颜色及其他样式,不失真 * 轻量,易修改 * 有效减少 HTTP 请求次数 ## 1.8 使用 base64 格式 ## 将图片转换为 `base64 编码字符串` inline 到页面或 css 中。 优点: * **提升性能**: 网页上的每一个图片,都是需要消耗一个 http 请求下载而来的, 图片的下载始终都要向服务器发出请求,要是图片的下载不用向服务器发出请求,base64 可以随着 HTML 的下载同时下载到本地.减少 https 请求。 * **加密**: 让用户一眼看不出图片内容 , 只能看到编码。 * **方便引用**: 在多个文件同时使用某些图片时, 可以把图片转为 base64 格式的文件, 把样式放在全局中, 比如 common.css, 以后在用的时候就可以直接加类名, 二不需要多层找文件路径, 会提升效率 但需要注意的是:如果图片较大,图片的色彩层次比较丰富,则不适合使用这种方式,因为该图片经过 base64 编码后的字符串非常大,会明显增大 HTML 页面的大小,从而影响加载速度。 base64 化最常见的就是在 url-loader 中使用: module.exports = { ... module: { rules: [ { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 10240, name: utils.assetsPath('img/[name].[hash:7].[ext]'), } }, ], }, } 这样就能将项目中小于 10kb 的图片转化为 base64 应用到页面中 ## 1.9 图片格式 ## ### 1.9.1 JPEG ### * JPEG 格式的图片可以`呈现数百万种颜色`。所以每当网站需要呈现色彩丰富的图片,JPEG 总是最佳选择。 * `有损压缩`,你可以通过压缩大大的减少图片的体积,一般图片用 60%级别比较合适,如果选择大于 75%的压缩等级,则会使图片有明显的质量下降。 * `无兼容性问题`,所以开发者可以放心随意使用。 使用场景: * JPG 适用于呈现色彩丰富的图片,在我们日常开发中,JPEG 图片经常作为`大的背景图`、`轮播图`或 `Banner 图`出现。 但是有损压缩后的图片确实很难露出马脚,当它处理矢量图形和 Logo 等线条感较强、颜色对比强烈的图像时,人为压缩的图片模糊会相当明显。 * JPEG 图像不支持透明度处理,透明图片可选择使用 PNG。 ### 1.9.2 PNG ### * PNG(可移植网络图形格式)是由 W3C 开发的图片格式,是一种`无损压缩`的`高保真`的图片格式。 * PNG 图片具有比 JPEG 更强的色彩表现力,对线条的处理更加细腻,对透明度有良好的支持。唯一的缺点就是`体积太大`。 应用场景: * PNG 在处理线条和颜色对比度方面的优势,我们主要用它来呈现`小的 Logo`、`颜色简单且对比强烈的图片或背景`等。 * 支持透明度处理,`透明图片`可选择使用 PNG ### 1.9.3 GIF ### * GIF 是一种`最多支持 256 种颜色`的 `8 位无损图片`格式。 * 支持 256 中颜色,文件体积通常都很小 * 支持透明 应用场景: * 支持动画,适合去展示一些无限循环的动画,比如`图标、表情、广告栏`等。 * 对于一些只有简单色彩的图片非常合适。 ### 1.9.4 WebP ### * WebP 是一种同时提供了`有损压缩`与`无损压缩(可逆压缩)`的图片文件格式,派生自影像编码格式 VP8。 * 它像 JPEG 一样对细节丰富的图片信手拈来,像 PNG 一样支持透明,像 GIF 一样可以显示动态图片,集多种图片文件格式的优点于一身。 * 虽然 webP 有诸多优点,但是它不能完全替代 JPEG 和 PNG,因为浏览器对 WebP 支持并不普遍。特别是移动端 IOS 系统基本不支持 ## 1.10 使用 CDN 图片 ## `CDN` (Content Delivery Network),即`内容分发网络`。CDN 是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN 的关键技术主要有`内容存储`和`分发技术`。 # 2. HTTP请求优化 # ## 2.1 减少HTTP请求次数 ## * 一个完整的 HTTP 请求需要经历 DNS 查找,TCP 握手,浏览器发出 HTTP 请求,服务器接收请求,服务器处理请求并发回响应,浏览器接收响应等过程。 * 减少HTTP请求次数,可以减少HTTP请求多余的浪费 ## 2.2 使用 HTTP2 ## * **解析速度快**:服务器解析 HTTP1.1 的请求时,必须不断地读入字节,直到遇到分隔符 CRLF 为止。而解析 HTTP2 的请求就不用这么麻烦,因为 HTTP2 是基于帧的协议,每个帧都有表示帧长度的字段。 * **多路复用**:在 HTTP2 上,多个请求可以共用一个 TCP 连接,这称为多路复用。 * **首部压缩**:HTTP/2 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送。 * **优先级处理**:HTTP2 可以对比较紧急的请求设置一个较高的优先级,服务器在收到这样的请求后,可以优先处理。 * **流量控制**:由于一个 TCP 连接流量带宽(根据客户端到服务器的网络带宽而定)是固定的,当有多个请求并发时,一个请求占的流量多,另一个请求占的流量就会少。流量控制可以对不同的流的流量进行精确控制。 * **服务器推送**:HTTP2 新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。 ## 2.3 使用服务端渲染 ## 服务端渲染:服务端返回 HTML 文件,客户端只需解析 HTML。 优点:首屏渲染快,SEO 好。 缺点:配置麻烦,增加了服务器的计算压力。 # 3. 减少重绘重排 # ## 3.1 浏览器渲染过程 ## 1. 解析`HTML`生成`DOM树`。 2. 解析`CSS`生成`CSSOM规则树`。 3. 解析`JS`,操作 `DOM 树`和 `CSSOM 规则树`。 4. 将DOM树与CSSOM规则树合并在一起生成`渲染树`。 5. `遍历渲染树`开始布局,计算每个节点的位置大小信息。 6. 浏览器将所有图层的数据发送给GPU,GPU将`图层合成并显示`在屏幕上。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZtazEwMjM_size_16_color_FFFFFF_t_70 1] ## 3.2 重绘重排 ## * **重排**:当改变 DOM 元素位置或大小时,会导致浏览器重新生成渲染树,这个过程叫重排 * **重绘**:当重新生成渲染树后,就要将渲染树每个节点绘制到屏幕,这个过程叫重绘。 * 不是所有的动作都会导致重排,例如改变字体颜色,只会导致重绘。记住,重排会导致重绘,重绘不会导致重排 * 重排和重绘这两个操作都是非常昂贵的,因为 JavaScript 引擎线程与 GUI 渲染线程是互斥,它们同时只能一个在工作 什么操作会导致重排? * 添加或删除可见的 DOM 元素 * 元素位置改变 * 元素尺寸改变 * 内容改变 * 浏览器窗口尺寸改变 如何减少重排重绘? * 用 `JavaScript` 修改样式时,最好不要直接写样式,而是替换 `class` 来改变样式。 * 如果要对 `DOM 元素`执行一系列操作,可以将 DOM 元素脱离文档流,修改完成后,再将它带回文档。推荐使用隐藏元素(display:none)或文档碎片(DocumentFragement),都能很好的实现这个方案。 # 4. 使用事件委托 # `事件委托`利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。所有用到按钮的事件(多数鼠标事件和键盘事件)都适合采用事件委托技术, 使用事件委托可以节省内存。 <ul> <li>苹果</li> <li>香蕉</li> <li>凤梨</li> </ul> // good document.querySelector('ul').onclick = (event) => { const target = event.target if (target.nodeName === 'LI') { console.log(target.innerHTML) } } // bad document.querySelectorAll('li').forEach((e) => { e.onclick = function() { console.log(this.innerHTML) } }) [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZtazEwMjM_size_16_color_FFFFFF_t_70]: /images/20220829/ea5dcd69adc94f3bb4c9f355791800ef.png [tinypng]: https://tinypng.com/ [Link 1]: https://zhitu.isux.us/ [squoosh]: https://squoosh.app/ [compressor]: https://compressor.io/ [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZtazEwMjM_size_16_color_FFFFFF_t_70 1]: /images/20220829/c5baecba91f14d1eb0177ecb824f9fb8.png
相关 前端性能优化 性能优化是把双刃剑,有好的一面也有坏的一面。好的一面就是能提升网站性能,坏的一面就是配置麻烦,或者要遵守的规则太多。并且某些性能优化规则并不适用所有场景,需要谨慎使用,请读者带 向右看齐/ 2023年01月17日 12:57/ 0 赞/ 12 阅读
相关 【前端性能优化】Webpack性能优化 目录 1. 什么是Webpack? 2. 提高构建速度 2.1 npm install 过程中的优化 ゞ 浴缸里的玫瑰/ 2022年12月04日 02:27/ 0 赞/ 484 阅读
相关 前端性能优化 减少请求数量 【合并】 如果不进行文件合并,有如下3个隐患 1、文件与文件之间有插入的上行请求,增加了N-1个网络延迟 2、受丢包问题影响更严重 港控/mmm°/ 2022年11月29日 00:55/ 0 赞/ 11 阅读
相关 前端性能优化-CSS性能优化 文章目录 一、内联首屏关键CSS 二、异步加载CSS 异步加载的几种方式 1.js动态创建样式表link元素,并插入到DOM中 ゞ 浴缸里的玫瑰/ 2022年11月13日 14:26/ 0 赞/ 433 阅读
相关 前端性能优化 前端性能优化 1. 减少HTTP请求 基本原理: > 在浏览器(客户端)和服务器发生通信时,就已经消耗了大量的时间,尤其是在网络情况比较糟糕的时候 布满荆棘的人生/ 2022年09月25日 10:26/ 0 赞/ 39 阅读
相关 前端性能优化 文章目录 1.图片优化 1.1 图片懒加载 1.2 图片预加载 1.3 响应式图片加载 1.4 渐进式图片 港控/mmm°/ 2022年09月07日 09:59/ 0 赞/ 90 阅读
相关 前端性能优化 第一部分 1、内容层面 DNS解析优化(DNS缓存、减少DNS查找、keep-alive、适当的主机域名) 避免重定向(/还是需要的) 偏执的太偏执、/ 2022年06月09日 10:30/ 0 赞/ 383 阅读
相关 前端性能优化 前端性能优化的方法:合并、压缩、缓存或者在服务器上开启gzip之类的,目的都是为了让页面加载的更快 资源预拉取(prefetch)则是另一种性能优化的技术。通过预拉取可以告诉 Dear 丶/ 2022年06月06日 10:25/ 0 赞/ 384 阅读
相关 前端性能优化 浏览器访问优化 浏览器请求处理流程如下图: ![v2-936b352a942f56296f5b3ecba09cd95e_hd.jpg][] 1、减少http 旧城等待,/ 2022年05月13日 11:22/ 0 赞/ 431 阅读
相关 前端性能优化 1. 减少 HTTP 请求数量 在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信。浏览器与服务器需要经过三次握手,每次握手需要花费大量时间。而且不同浏览器对资源文 拼搏现实的明天。/ 2021年11月01日 21:20/ 0 赞/ 575 阅读
还没有评论,来说两句吧...