Hexo - 性能优化之旅
看不见的地方一样重要,主题性能优化相关专题。
前几天面试问了性能优化,好久没关注这块了,许多操作就想不起来,很尴尬……
所以本文总结一下 hexo-theme-zhaoo
主题中做的一些性能优化,主要从 用户体验 、网络请求 、视图渲染 三方面入手,作者借此复习一下,逃。
用户体验
在做性能优化的时候,我们总是会关注各种指标:请求速度、渲染速度、白屏时间……这些优化固然重要,但是我们往往会忽略 用户体验,从用户角度来看可能体验才是最重要的。
试想:你的网站刚上线,并没有做任何优化,此时首屏加载时间需要 8s 。很遗憾,大多数用户没有这个耐心等待,会选择点击右上角的 X ,并且拉入了“黑名单”。这样可不行,然后你就做了一些常规优化,轻轻松松就将首屏加载时间拉到了 2s ,用户粘性就上来了。这时候你还不满足,执着于各种性能指标,通过一套“牛X”的算法把加载时间优化到了 1.5s 。过程可能很艰辛,但是结果却不是很理想,因为对于大多数用户来说可能根本感受不到这 0.5s 之间的差别。当你绝望的时候,UI小姐姐甩过来一张 Loading
图,你随手一加,结果用户量猛增。
从用户心理角度来说,从按下回车到首屏展示这段时间(白屏),他是最不安的,觉得这个网站随时可能挂掉。你甩出一个 Loading
动画让他“欣赏”,他起码会觉得这个网站还在动,大不了多看会儿嘛。
所以我们做优化的时候要兼顾 用户体验 ,而不是一昧的追求速度。
Loading
思路很简单,页面头部首先加载 Loading
遮罩图(HTML + CSS),在页面底部加载 JS
后,通过 JS
把 Loading
遮罩移除即可。
考虑到用户体验,提供一个较为稳定的动画时间,而不是一闪而过,所以给了 0.5s 延时。同时埋了个点,可以在 _config.yml
中配置自己的 Loading
效果。
渐进动画
网络请求
Promise 并发控制
这是一道“字节”必考题,面经背了学以致用吧。
主题使用 leancloud
来存储浏览量(PV),在进入页面的时候会并发请求获取浏览量。会产生以下问题:1. 并发请求会被服务器阻塞,返回 429
错误。2. 由于请求被阻塞了,页面渲染也被JS引擎阻塞了,产生 1s 左右的延迟。
为了解决这一问题,我们可以引入 Promise
并发控制请求流量,控制一次性不会涌入大量请求。
CDN
静态资源从服务器下载到用户主机,需要经过许多路由,一般距离越远,速度越慢。CDN(内容分发网络) 就是将资源部署到空间分布于各地的服务器上,用户访问时从就近的服务器拉取资源,起到加速作用。还可充当 负载均衡 、 缓存备份 功能。(以上是官方说法,我们哪来那么大的流量,纯粹是因为学生服务器太渣了,上行速度实在是太慢,架不住资源)
CDN
直接用云服务商的就好了,阿里云、腾讯云、七牛云、又拍云…… 好,我选择免费的七牛云,HTTPS
每个月也就五毛钱。
部署方式很简单,创个账号,建个空间,绑个域名,传个文件,网上一堆教程。
VSCode
版很方便。众所周知:VSCode
除了码代码啥都可以干。
另外,JS
和 CSS
等静态资源,我们就不用存自己的 CDN
空间了,BootCDN 更方便。我在主题埋了个点,直接填写链接即可,不填默认从本地获取。
Gzip
服务器层面,应该开启 Gzip
压缩,能将文件资源体积压缩到原来的 1/4 。注意不要对图片资源进行压缩,适得其反,所以在配置项 gzip_types
中进行选择。
(宝塔面板偷个懒)
async / defer
【亲测效果很好】
我们知道,GUI渲染线程 和 JS引擎线程 是互斥的,同时执行会导致渲染混乱,所以默认将他们分离执行。运行到 <script>
标签(包括加载脚本)时会暂停渲染,浪费了一些性能。(这也是我们提倡将 <style>
放在头部,将 <script>
放在底部的原因之一)
为了压榨性能呢,w3c
为我们提供了两个属性:async
、 defer
,可以帮助我们异步加载脚本。(周立齐:执行异步是不可能,这辈子都不可能的)
- default:同步加载脚本
- aysnc:异步加载脚本,加载完马上执行
- defer:异步加载脚本,页面渲染后执行
盗了张图,一图胜千言:
优化思路:
- 把一些渲染过程中用不到的第三方脚本打上
defer
,拖到渲染后执行。 - 把渲染中需要使用的脚本打上
async
,异步加载。(需要注意顺序,不要打乱执行流程)
优雅一点嘛~
像 评论 、 请求统计 、 DaoVoice 这些第三方脚本加载巨慢,特别是 leancloud
,延迟大约 1s 多,严重拖慢了渲染速度。套上 async/defer
之后感觉棒棒哒~
loadScript
一些例如 实例化 、 挂载 等执行逻辑,需要依赖前置脚本加载完后才能执行。这时候如果给它俩都套上了 async/defer
,异步执行顺序就会不可控,会报一些 underfined
之类的错。
所以我们需要改造一下,让它们链式触发。最简单的思路就是借助回调函数了,可以直接使用 jQuery
的 $.ajax()
实现。但是我后期考虑移除 jQuery
,还是自己封装一下吧。
最简单的加载方式是 loadScript
,通过操纵 DOM
, append
一个 <script>
标签来加载资源。
食用方式:
AJAX
阿贾克斯年代了, loadScript
也太逊了吧……
之后可能会考虑移除 jQuery
, 那就先封装一个 Ajax
吧:
PJAX
这是个反面教材……
PJAX
可以理解为 AJAX
的升级版。AJAX
只是简单的异步请求资源,一般用于局部无刷新加载,如果用于整页加载会造成 URL
无法更新,从而影响 SEO
和 回退操作。而 PJAX
基于 AJAX
和 pushState
(其实就是前端路由那两套方案),可以改变 URL
,可以提供了整页无刷新加载。
缓存
PWA
视图渲染
静态脚本移到编译阶段
减少重绘回流
图片懒加载
懒加载就是图片延迟加载,先套个占位图,等图片 进入视口后 或者 快进入时候时(通过加一定高度预判,预加载) 才加载并渲染图片。
实现思路:
- 在编译阶段进行劫持,将
HTML
中的img
标签中的src
图片地址保存到data-src
进行缓存,同时替换为占位图(Loading)。 - 运行阶段,图片进入视口后,再将
src
替换为data-src
加载图片。(暂时用了第三方懒加载库,立个Flag,日后定要造个轮子)
图标
- 本文作者:zhaoo
- 本文链接:https://www.izhaoo.com/2020/08/08/hexo-performance-optimization/index.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!