首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >重学前端之前端需要了解的性能优化方向

重学前端之前端需要了解的性能优化方向

原创
作者头像
一起重学前端
发布2024-12-01 11:05:00
发布2024-12-01 11:05:00
1830
举报

“好事”文章推荐:《『学习笔记』如何使用Nginx搭建高并发Web服务器》

文章地址:https://cloud.tencent.com/developer/article/2472065

好文介绍:本讲介绍通过 Nginx 的一系列优化配置后,系统整体性能显著提升,不仅满足了购物节高并发流量需求,还提升了用户满意度。通过 Nginx 的优化配置,可以显著提升 Web 服务器的并发处理能力和用户体验。在实际部署中,需要根据业务特点灵活调整参数,确保性能与稳定性的平衡。值得一看

CDN

CDN(Content Delivery Network,内容分发网络)指的是一组分布在各个地区的服务器。

这些服务器存储着数据的副本,因此服务器可以根据哪些服务器与用户距离最近,来满足数据的请求。

CDN 提供快速服务,较少受高流量影响。

假设有一部影片出版,非常多人看。jsliang 在广州,请求上海的服务器,结果这个服务器非常多人,资源响应地很慢。于是 jsliang 切换了路线,看到深圳服务器也有这个资源,于是向深圳服务器请求,结果能很快地看到这部影片。

在这个场景中,深圳服务器就扮演 CDN 的角色。

CDN 的核心:缓存回源

  • 缓存:将资源 copy 一份到 CDN 服务器。
  • 回源:CDN 发现自己没有这个资源,转头向根服务器(上级服务器)请求这个资源。

应用场景:

  1. 公司静态资源部署到就近的服务器,利用 CDN 特性方便访问
  2. jQuery 等框架可以引用 CDN,加快网站的加载速度,避免同一个服务器加载的限制。
  3. 减少 Cookie 影响。同一个域名下,请求静态资源会携带 Cookie 信息,但是我们并不需要,所以使用 CDN 可以避免不必要的 Cookie 出现场景。

负载均衡

如果是大型网站,负载均衡是不可或缺的内容。

  • PM2:一款 Node.js 进程管理器,让计算机每一个内核都启动一个 Node.js 服务,并且实现自动控制负载均衡。
  • Nginx:通过轮询机制,将用户的请求分配到压力较小的服务器上(反向代理)。

区别:反向代理是对服务器实现负载均衡,而 PM2 是对进程实现负载均衡

Webpack 优化

  • 优化 resolve.modules 配置

resolve.modules 用于配置 Webpack 去哪些目录下寻找第三方模块,默认是 'node_modules',但是,它会先去当前目录的 ./node_modules 查找,没有的话再去 ../node_modules,最后到根目录。

代码语言:js
复制
  resolve: {
      modules: [path.resolve(__dirname, 'node_modules')],
  }
  • 优化 resolve.extensions 配置

在导入没带文件后缀的路径时,Webpack 会自动带上后缀去尝试询问文件是否存在,而 resolve.extensions 用于配置尝试后缀列表;默认为 extensions:'js', 'json'。

当遇到 require('./data') 时 Webpack 会先尝试寻找 data.js,没有再去找 data.json;如果列表越长,或者正确的后缀越往后,尝试的次数就会越多。

所以在配置时为提升构建优化需遵守:

  1. 频率出现高的文件后缀优先放在前面。
  2. 列表尽可能的少,例如只有 3 个:js、jsx、json。
  3. 书写导入语句时,尽量写上后缀名。
  4. babel-loader

babel-loader 为例,可以通过 include 和 exclude 帮助我们避免 node_modules 这类庞大文件夹。

  • tree shaking

通过 ES6 的 import/export 来检查未引用代码,以及 sideEffects 来标记无副作用代码,最后用 UglifyJSPlugin 来做 tree shaking,从而删除冗余代码。

  • 多进程

Happypack 可以将任务分解成多个子进程去并发执行,大大提升打包效率。消耗性能,不用建议关闭。

  • 多进程代码压缩

因为自带的 UglifyJsPlugin 压缩插件是单线程运行的,而 ParallelUglifyPlugin 可以并行执行。

所以通过 ParallelUglifyPlugin 代替自带的 UglifyJsPlugin 插件。

  • 抽离

通过 DllPlugin 或者 Externals 进行静态依赖包的分离。

由于 CommonsChunkPlugin 每次构建会重新构建一次 vendor,所以出于效率考虑,使用 DllPlugin 将第三方库单独打包到一个文件中,只有依赖自身发生版本变化时才会重新打包。

  • 打包资源压缩
  • JS 压缩:UglifyJSPlugin
  • HTML 压缩:HtmlWebpackPlugin
  • 提取公共资源:splitChunks.cacheGroups
  • CSS 压缩:MiniCssExtractPlugin
  • Gzip 压缩:不包括图片
  • 拆包

SplitChunksPlugin

  • 按需加载

通过 Code-Splitting 来做 React 的按需加载.

Code_Splitting 核心是 require-ensure

图片优化

  • JPEG 与 JPG

关键字:有损压缩、体积小、加载快、不支持透明

优点:压缩一定程度能保持品质、体积小、请求速度快

缺点:处理矢量图形、Logo 等线条感较强,颜色对比强烈的图形,人为压缩会导致图片模糊明显。不支持透明度处理。

使用场景:大的背景图、轮播图或者 Banner 图。

  • PNG-8 与 PNG-24

关键字:无损压缩、质量高、体积大、支持透明

优点:PNG-8 支持 256 种颜色,PNG-24 支持 1600 种颜色。更强的色彩表现力,对线条的处理更加细腻,对透明度有良好的支持。

缺点:体积较大

使用场景:Logo、颜色简单且对比强烈的图片和背景。

  • GIF

关键字:动态图、体积小支持透明

优点:可以压缩体积非常小。可插入多帧实现动画效果。支持透明色浮现于背景之上。

缺点:最多只能处理 256 中颜色,不适用于真彩图像。

使用场景:小动画。

  • SVG

关键字:文本文件、体积小、不失真、兼容性好

优点:文本体积更小,可压缩性更强。图片可以无限放大不失真。文本文件可以直接在 HTML 中写入,灵活性高。

缺点:渲染成本高、学习成本(可编程)

使用场景:变成代码嵌入 HTML 中,也可以换成 .svg 后缀的文件进行引用。

  • Base64

关键字:文本文件、依赖编码、小图标解决方案

优点:作为雪碧图的补充而存在,减少加载页面图片时对服务器的请求次数。(img src 会发起资源请求,但是 Base64 得到的是字符串,嵌入 HTML 中)

缺点:大图使用 Base64 会增大体积,影响性能

使用场景:小 Logo(不超过 2kb)、更新频率低的图片。

编码工具:Webpack 的 url-loader 可以根据文件大小来判断是否编码成 Base64。

  • 雪碧图

雪碧图、CSS 精灵、CSS Sprites、图像精灵,都是同一个玩意。

它是将小图标和背景图像合并到一张图片上,然后通过 CSS 背景定位来显示其中的每一个具体部分。

它是一种优化手段,因为单张图片所需的 HTTP 请求更少,对内存和带宽更加友好。

  • WebP

关键字:年轻的全能型选手

优点:支持有损压缩和无损压缩、支持透明、可以跟 GIF 一样显示动态图

缺点:兼容性差

使用场景:暂无大型应用场景

Gzip 压缩

  • Webpack 开启 Gzip

通过 compression-webpack-plugin 可以开启 Gzip 压缩。

  • 是否值得开启 Gzip

如果压缩文件太小,那不使用;但是如果具有一定规模的项目文件,可以开启 Gzip。

  • Gzip 原理

Gzip 并不是万能的,它的原理是在一个文本文件中找一些重复出现的字符串、临时替换它们,从而使整个文件变小,所以对于图片等会处理不了。

  • 服务器端和 Webpack 的 Gzip 并存

服务器压缩也需要时间开销和 CPU 开销,所以有时候可以用 Webpack 来进行 Gzip 压缩,从而为服务器分压。

服务端渲染

  1. 首屏或其他模块加载速度快、
  2. 为了更好的 SEO 效果
  3. 如何给 React 开启服务端渲染
  4. 如何给 Vue 开启服务端渲染

SSR 主要用于解决单页应用首屏渲染慢以及 SEO 问题

但同时:提高了服务器压力,吃 CPU,内存等资源,优化不好提高成本。

浏览器渲染机制

  • 优化 - CSS 选择器问题
代码语言:css
复制
#ul li {}

实际上 CSS 解析器是从右往左的,它会先查找所有 li 元素,并且逐个确认这个 li 元素的父元素的 id 是不是 ul。

所以像通配符 * { padding: 0; margin: 0 } 这种,小伙伴们就应该减少设置,要不然页面的元素越多遍历匹配越久。

  1. 避免使用通配符 * 等。
  2. 减少使用标签选择器,用类选择器或者标签选择器替代,例如 span 替换为 .span。
  3. 减少嵌套匹配,例如 #ul li a。
  4. 优化 - CSS 加载问题

为了避免 HTML 解析完毕,但是 CSS 没有解析完毕,从而导致页面直接 “裸奔” 在用户面前的问题,浏览器在处理 CSS 规则树的时候,不会渲染任何已处理的内容。

所以很多时候,我们会让网页尽早处理 CSS,即在 head 标签中启用 link 或者启用 CDN 实现静态资源加载速度的优化。

  • 优化 - JS 加载问题

当 HTML 解析器遇上 script 标签时,它会暂停解析过程,将控制器交给 JS 引擎。

如果是内部的 JS 代码,它会直接执行,但是如果是 src 引入的,还要先获取脚本,再进行执行。

等 JS 引擎执行完毕后,再交接给渲染引擎,继续 HTML 树和 CSS 规则树的构建。

  1. 如果 JS 和 DOM 元素或者其他 JS 代码之间的依赖不强的时候,使用 async
  2. 如果 JS 依赖于 DOM 元素和其他 JS 的执行结果,那就使用 defer
  3. 优化 - DOM 渲染问题

当使用 JS 去操作 DOM 的时候,实际上是 JS 引擎和渲染引擎之间的沟通,这个沟通的过程要开销的。

同时,操作 DOM 的时候修改了尺寸等元素,还会引起回流重绘

  1. 【CSS】使用 visibility 替换 display
  2. 【CSS】避免 table 布局。对于 Render Tree 的计算通常只需要遍历一次就可以完成,但是 table 布局需要计算多次,通常要花 3 倍于等同元素的时间,因此要避免。
  3. 【JS】避免频繁做 width、height 等会触发回流的操作。
  4. 【JS】操作 DOM 的时候,如果是添加 DOM 节点,可以将所有节点都在 JS 中操作完毕,再进行渲染(一次性)。

预加载页面资源

preload 提供了一种声明式的命令,让浏览器提前加载指定资源(加载后并不执行),在需要执行的时候再执行。

代码语言:html
复制
<!-- 使用 link 标签静态标记需要预加载的资源 -->
<link rel="preload" href="/path/to/style.css" as="style">

preload 和 prefetch:

  • preload:告诉浏览器页面必定需要的资源,浏览器一定会加载这些资源。
  • prefetch:告诉浏览器页面可能需要的资源,浏览器不一定会加载这些资源。

长列表

  • 懒加载
  • 虚拟列表(可视区域渲染)

无限滚动在移动端很常见,但是可见区域渲染并不常见,主要是因为 IOS 上 UIWebView 的 onscroll 并不能实时触发。

实现可见区域渲染的思路:

  1. 计算当前可见区域起始数据的 startIndex
  2. 计算当前可见区域结束数据的 endIndex
  3. 计算当前可见区域的数据,并渲染到页面中
  4. 计算 startIndex 对应的数据在整个列表中的偏移位置 startOffset,并设置到列表上

未完待续,持续更新中...

感谢关注点赞评论~

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CDN
  • 负载均衡
  • Webpack 优化
  • 图片优化
  • Gzip 压缩
  • 服务端渲染
  • 浏览器渲染机制
  • 预加载页面资源
  • 长列表
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档