在三个多月的春招历程中 , 经历了多家面试 , 面试中变与不变的核心往往就是那些 , 虽然终究是0offer , 但也把自己的一些感悟总结出来 , 大佬勿喷 , 希望能在评论区指出我的不足 .
性能优化之总览
图片引用修言大佬的掘金小册
为什么要学习性能优化? 这是轻流面试官问我的一个问题 . 面试中聊到了对数据懒加载 , 图片懒加载相关的点 , 被问及为什么要这么做 . 我当时的回答是 , 虽然自己的项目中数据量并不庞大 , 但是自己在学习中了解到性能优化相关知识 , 便想动手实践 , 所以在自己的项目中也使用了相关技术 .
现在回想一下 , 为什么学性能优化 ? 我只是认为这是一个前端coder 所应了解的基础知识罢了 , 随着前端的不断发展 , 从最开始的无模块化 , 到组件化 , 模块化 , 智能化 , 前端的项目已然十分庞大 , 接触的业务也越来越难 , 而性能优化就显得尤为重要 , 性能优化也是当下编码者需要了解的最基础知识 , 它与数据结构 , 算法 , 计算机网络 , 设计模式等知识一样 , 都是我们的内功 . 是变与不变的知识潮流中的不变量 .
在我看来 , 性能优化大体在网络层面以及渲染层面 .
网络层面
涉及到网络层面 , 在我的认知中 , 项目打开到渲染展示中 , 最耗时的就是发送请求再到取到数据的过程 .
就像经典面试题 从输入url到页面展示做了哪些事?
大家肯定十分熟悉 :
- 首先判断url是否合法 , 来决定是跳转or搜索
- 其次就是缓存判断 , 强缓存与协商缓存的取舍 , 以及协商缓存中的返回码(304)或者取到服务器资源再替换本地缓存(200)
- 再就是DNS解析 , 域名->ip
- TCP三次握手
- HTTP请求
- 服务器收到请求处理并返回报文
- 浏览器解析渲染
- TCP4次挥手
无非就是这些老东西 , 从这个问题也能牵出各个经典面试题 , 来考察我们的基础知识以及对浏览器原理的掌握 .
而性能优化的大头就在以上几点中
缓存
强缓存
强缓存是当我们访问URL的时候,不会向服务器发送请求,直接从缓存中读取资源,但是会返回200的状态码。
强缓存的字段
Expires 强缓存是利用 http 头中的 Expires (时间戳)和 Cache-Control (时间长度)两个字段来控制的。强缓存中,当请求再次发出时,浏览器会根据其中的 expires 和 cache-control 判断目标资源是否“命中”强缓存,若命中则直接从缓存中获取资源,不会再与服务端发生通信。
public 与 private
public 与 private 是针对资源是否能够被代理服务缓存而存在的一组对立概念。
如果我们为资源设置了 public,那么它既可以被浏览器缓存,也可以被代理服务器缓存;如果我们设置了 private,则该资源只能被浏览器缓存。private 为默认值。
no-store与no-cache
no-cache 绕开了浏览器:我们为资源设置了 no-cache 后,每一次发起请求都不会再去询问浏览器的缓存情况,而是直接向服务端去确认该资源是否过期(即走我们下文即将讲解的协商缓存的路线)。
no-store 比较绝情,顾名思义就是不使用任何缓存策略。在 no-cache 的基础上,它连服务端的缓存确认也绕开了,只允许你直接向服务端发送请求、并下载完整的响应。
协商缓存
协商缓存就是强缓存失效后,浏览器携带缓存标识向服务器发送请求,由服务器根据缓存标识来决定是否使用缓存的过程。
协商缓存的字段
Last-Modified 是一个时间戳,如果我们启用了协商缓存,它会在首次请求时随着 Response Headers 返回:
随后我们每次请求时,会带上一个叫 If-Modified-Since 的时间戳字段,它的值正是上一次 response 返回给它的 last-modified 值:
服务器接收到这个时间戳后,会比对该时间戳和资源在服务器上的最后修改时间是否一致,从而判断资源是否发生了变化。如果发生了变化,就会返回一个完整的响应内容,并在 Response Headers 中添加新的 Last-Modified 值;否则,返回如上图的 304 响应
Last-Modified 存在一些弊端
●我们编辑了文件,但文件的内容没有改变。服务端并不清楚我们是否真正改变了文件,它仍然通过最后编辑时间进行判断。因此这个资源在再次被请求时,会被当做新资源,进而引发一次完整的响应——不该重新请求的时候,也会重新请求。
●当我们修改文件的速度过快时(比如花了 100ms 完成了改动),由于 If-Modified-Since 只能检查到以秒为最小计量单位的时间差,所以它是感知不到这个改动的——该重新请求的时候,反而没有重新请求了。
为了解决这样的问题,Etag 作为 Last-Modified 的补充出现了。
Etag 是由服务器为每个资源生成的唯一的标识字符串,这个标识字符串是基于文件内容编码的,只要文件内容不同,它们对应的 Etag 就是不同的,反之亦然。因此 Etag 能够精准地感知文件的变化。
请求
网页从跳转到展示 , 发送请求的时间总是占大头 , 而我们要对这段时间进行优化 .
请求所带来的知识则更多 , 请求的资源优化 , 构建工具的优化 , 本地存储等 .
构建工具
webpack , 前端难以逃避的一个点 . 虽然新秀vite很棒 , 用起来很润 , 但是我们也只会在开发环境选择vite , 而在真正上线时候选择webpack .
webpack打包优化
1.优化loader转译范围
2.使用 DllPlugin 对三方库进行单独打包
3.使用Happypack 将loader从单进程转化为多进程
4.摇树优化 基于ESmoudle Tree-Shaking 可以在编译的过程中获悉哪些模块并没有真正被使用,这些没用的代码,在最后打包的时候会被去除。
5.路由按需加载 require.ensure(dependencies, callback, chunkName) 或者 箭头函数 + import
6.Gzip压缩 请求头中添加 accept-encoding : Gzip
请求资源的优化
图片的压缩
图片格式的正确选择很重要
1.JPG显示大图
2.小图Base64 通过对图片进行 Base64 编码,我们可以直接将编码结果写入 HTML 或者写入 CSS,从而减少 HTTP 请求的次数。
3.在浏览器环境支持 WebP 的情况下,优先使用 WebP 格式,否则就把图片降级为 JPG 格式(本质是对图片的链接地址作简单的字符串切割)。
CDN
CDN(Content Delivery Network,即内容分发网络)指的是一组分布在各个地区的服务器。这些服务器存储着数据的副本,因此服务器可以根据哪些服务器与用户距离最近,来满足数据的请求。 CDN 提供快速服务,较少受高流量影响。
CDN 往往被用来存放静态资源。它的核心任务在于生成动态页面或返回非纯静态页面
所谓“静态资源”,就是像 JS、CSS、图片等不需要业务服务器进行计算即得的资源。而“动态资源”,顾名思义是需要后端实时动态生成的资源,较为常见的就是 JSP、ASP 或者依赖服务端渲染得到的 HTML 页面。
本地存储
老三样: cookie , loaclstorage , sessionstorage .
再进阶则是IndexedDB .
而我只了解老三样 , 老三样的面试题又会涉及到她们的不同 , cookie的跨越 , 以及同源页面的数据传递 , 或者组件以及数据的持久化等 . 学习本地存储的目的 , 就是榨干浏览器的每一寸 , 应对不同的业务 , 合理使用本地存储尤为重要 .
渲染层面
浏览器渲染原理
浏览器渲染 , 此时又会有核心面试题 , 浏览器渲染原理
这时候基本大家都会知道 , html解析DOM树 , css解析样式树 , 两树组合生成render树 , 然后在进行布局 , 从根节点递归调用,计算每一个元素的大小、位置等,给每个节点所应该出现在屏幕上的精确坐标,得到了基于渲染树的布局渲染树 , 最后以布局渲染树为蓝本,去计算布局并绘制图像 .
重点来了 , 这时候会看到关键字 : html , css , 布局 , 绘制 . 我们的优化也是基于此开始 .
涉及到这些 , 首先肯定是html 与 css的优化 , 回流重绘的减少 , 包块代码结构的优化 , 以及文件的压缩 , js的异步 , 事件循环 , 异步更新 , 这些都是老生常谈 , 而我只提一下比较冷门的部分 . 关键渲染路径的优化 .
关键渲染路径 , 包括(1)关键资源的数量 (2)关键路径长度 (3)关键字节的数。
优化关键渲染路径的常规步骤如下:
(1)对关键路径进行分析和特性描述:资源数、字节数、长度。
(2)最大限度减少关键资源的数量:删除它们,延迟它们的下载,将它们标记为异步等。
(3)优化关键字节数以缩短下载时间(往返次数)。
(4)优化其余关键资源的加载顺序:您需要尽早下载所有关键资产,以缩短关键路径长度
SSR
服务端渲染则牵扯出另一个知识点 , 客户端渲染 . 最早的时候 , 其实前端都是服务端渲染 , 以前后端不分离的形式进行开发 , 而时代的发展 , 前后端分离 , 单页面应用兴起 , 客户端渲染也开始出现 . 而为什么现在又要使用服务端渲染呢 ?
这是因为某些项目需要很好的支持seo , 并且需要更快的首屏加载 .
客户端渲染
客户端渲染模式下,服务端会把渲染需要的静态文件发送给客户端,客户端加载过来之后,自己在浏览器里跑一遍 JS,根据 JS 的运行结果,生成相应的 DOM。这种特性使得客户端渲染的源代码总是特别简洁,
页面上呈现的内容,你在 html 源文件里里找不到——这正是它的特点。
服务端渲染
服务端渲染的模式下,当用户第一次请求页面时,由服务器把需要的组件或页面渲染成 HTML 字符串,然后把它返回给客户端。客户端拿到手的,是可以直接渲染 HTML 内容,不需要再跑一遍 JS 代码。
使用服务端渲染的网站,可以说是“所见即所得”,页面上呈现的内容,我们在 html 源文件里也能找到。
结语
暂时我所了解的性能优化只能想起这些了 . 其中或许会有很多不足与错误希望大佬能够在评论区补出 .
有需要看面试题总结的小伙伴 , 可以进入我的语雀 www.yuque.com/u25385678
大环境不好 , 愿大家不断努力 , 提升自己才能走向更好的生活 .