我的网页加载速度优化:看似无用所学,终有用武之地

2022年7月21日 · 2 years ago

我的博客加载速度优化:看似无用所学,终有用武之地

前段时间给我的博客做了一下加载速度优化,同事笑称我的“优化”都是好几百年前的技术了😂。不过我很多年没有认真做前端了,这个博客 justinyan.me 搬过几次Server,但一直用的是Wordpress,接入是Nginx。除了最近两年把图片搬到腾讯云CDN之外就没做过什么优化,也难怪要被同事嘲笑。

以下是我对这个陈年老博客做过的优化,有些是之前做过的,记录一下供以后参考。这些想必早成前端基础,专业人士莫笑。😁

P.S. 这篇文章是6月份开始写的,7月18日我们发布了《中文播客榜》xyzrank.com也用上了了所有的优化,现在想来,技术的东西总是一开始折腾,后来就成为下一个项目的基础了。

一、把静态资源搬到CDN

cdn

一般是图片、音频、视频等较大体积的资源,不会跟着 HTML 一起接收的,就托管到 CDN 上。JS/CSS 等一般不怎么变化的文件也可以托管到 CDN 上。

早年间JS/CSS文件由服务器直接host,我们一般在URL后面加上 ?version=xxx 参数来解决浏览器缓存问题。现在要搬上CDN就不能这么干了,因为CDN缓存的是文件,跟URL的query无关。这时候就需要用上Webpack的content hash来解决这个问题。

我现在建站一般使用Webpack或Vite (for Vue 3项目)作为流程构建工具,如果大家使用Webpack的话,可以参考官方文档: Caching | webpack

webpack config content hash

原理是为正式环境编译文件时,根据文件内容计算content hash并作为URL路径的一部分,这样每次修改代码hash就会变,浏览器和CDN的Cache也就跟着变了。

CDN 服务的话,如果面向的用户群体在国内的话,建议选择国内的云服务,腾讯云,阿里云,七牛,又拍云等非常多可选。虽然国外的 Cloudflare 有免费的 CDN 额度,但是因为众所周知的原因,如果想要国内用户有较好的浏览体验的话还是用国内的吧。

另外想用国内的 CDN 服务需要走“各种繁琐的手续”,但(¯_(ツ)_/¯),还是走一遍吧。

搞定 CDN 服务之后,Wordpress上我安装了 CDN Enabler 插件,它做的事情就是在下发 HTML 之前,把我文章里所有的 https://justinyan.me 开头的 URL,替换成我的 CDN 域名。非常简单。

其他静态站点可以直接手动传到CDN,想做自动化的话一般各家都有自己的SDK可用。我的 Just Focus for Mac就是自己写了脚本,一键编译,打包,自动上传CDN,更新Server地址的。(感谢前同事 @dangrover多年前给我介绍的 The Joel Test: 12 Steps to Better Code – Joel on Software,自那以后我所有的项目都必须支持一键编译部署。)

二、使用Lighthouse找出优化点

lighthouse

刚开始工作的时候我针对公司项目一个大文件读取进行了优化,因为读取量是以前的三分之一,所以我当时跟我的 Leader 说我的优化效果理论上可减少三分之二的耗时,性能提升三倍。我的 Leader 跟我说,优化必须要有数据,不能靠猜,所以需要跑一下 Profile 来证明我的结论。

自那以后我就记得,一切优化必须有数据做支撑,否则你也许做了负优化都未可知。

前端的优化工具很多,Chrome 自带的 Dev Tools 里就有个超好用的 Lighthouse 工具,可以帮我们分析出当前页面存在的问题。Lighthouse分为几个大项:

  1. Performance
  2. Accessibility
  3. Best pratices
  4. SEO
  5. Progressive Web App

为了减少缓存优化带来的误判,建议在“隐身模式”(Incognito)下运行。跑完一次分析之后,工具会给出各种相关的优化建议。

  1. First Contentful Paint
  2. Time to Interactive
  3. Speed Index
  4. total Blocking Time
  5. Largest Contentful Paint
  6. Cumulative Layout Shift

每一项点开都会有更具体的优化策略,十分贴心。大家只需根据 Lighthouse 的建议进行优化即可。

三、CDN和Nginx开启HTTP/2

http2-nginx

HTTP/2 的多路复用(Multiplexing)可以使用一个连接发起多个请求,在需要并发请求大量资源(JS/CSS/Images/…)的 Web 场景可以大幅缩短页面请求时长。

关于 HTTP/2 的直观效果大家可以参考一下Akamai这个demo。至于HTTP/2能否直接上线呢?可以参考 CanIUse.com,已经是非常成熟的技术了。

使用 wordpress.com 或其他平台服务提供的博客通常不需要管到这么具体的配置,自建站点如果使用了“各种面板”一般也会帮你打开。

手动安装部署 Nginx 的小伙伴可以看一下自己的 nginx conf 有没有开启 http2。

在 Linux 服务器上先找到自己博客域名的配置文件:

sudo vim /etc/nginx/sites-available/xxxx.com

也有可能在 sites-enabled 目录。

编辑域名配置文件,在 listen 后面加上 http2 即可:

  listen 443 ssl http2; 

编辑完记得 reload 一下:

sudo service nginx reload

除了站点配置之外,CDN 的配置也记得打开:

四、CDN和Nginx开启文本Gzip压缩

gzip

我们知道 html/js/css/json 都是纯文本资源,纯文本就存在压缩空间。现在 Gzip 压缩在各种主流浏览器已经非常普及了。所以我们可以在后台开启 Gzip 压缩支持,当客户端的 HTTP 请求头带有 Accept-Encoding: gzip 时,我们就可以返回使用 gzip 压缩过的包。可以参考 MDN 的文档: Accept-Encoding - HTTP | MDN

gzip 的原理很有意思,大致是利用了人类语言中的“重复性”,通过把重复的片段提取出来,以backpointers形式进行编码,然后再进行霍夫曼编码得出压缩后的文本,可以达到惊人的 70-90% 压缩率。也因此 gzip 对于不怎么具有重复性的二进制数据效果不佳,对于已经混淆压缩过的各种 .min.js 的效率也会低于原文:Optimizing Encoding and Transfer Size of Text-Based Assets

Joshua Davies的这篇长文 Dissecting the GZIP format 对Gzip算法进行非常详尽的解释,超级棒,有兴趣的小伙伴可以留言扣个 1 我有空可以翻译一下(挖坑小能手)。

总而言之言而总之,服务端开启 gzip 就完事了。

五、对图片资源进行处理

tinypng

我们在 Web 中难免用到大量 jpg/png 格式的图片,所以第一步是确保上线前这些图片资源都经过合适的压缩。在保证图片质量的前提下尽量将体积压缩到最小

最常使用到的服务无疑是 tinypng.com 啦。tinypng有开放 API,也有 Figma 插件,Wordpress 插件,免费额度已经非常足够,大家自行上官网取用即可。

压缩完图片之后我们还需要对 <img> 标签进行 Lazy Loading 懒加载优化

浏览器的默认行为是解析完 DOM 发现有 <img> 就直接请求图片,即便这些图片并未被渲染在屏幕上。很多人进来看文章,还没看到图片就关掉页面了,这时候这些请求不仅导致浏览器体验不佳,还会浪费CDN流量。

现在大部份浏览器都支持 loading="lazy" 的写法,可以参考:Lazy loading - Web Performance | MDN 这篇文章。

如果嫌浏览器的行为不够激进的话,还可以使用Lozad.js这样的库实现更激进的图片懒加载。

六、使用WebP格式的图片取代jpg/png

webp format

Webp 是 Google 推出的一种图片格式,同等显示质量下,可比 PNG 小 26%,比JPEG 小 25-34%(参考这里)。

并不是所有浏览器都支持 Webp,所以我们可以使用各种云服务提供的云端转码能力,当浏览器支持 Webp 时,向云端请求 Webp 格式的图片。

比如数据万象简介-腾讯云这样的接口,数据万象应该在国内各家云服务都有接口,大同小异,大家根据自己购买的云服务查看文档即可。

一般可在对应 CDN 的图片文件 URL 末尾拼接参数实现:

https://xxxx.png?imageMogr2/format/webp

具体支持的参数与收取费用大家查看文档即可。

七、缓存静态HTML

html cache

虽然我的博客是个“动态网站”,但我更新并不频繁,也没多少可实时变更的数据。所以大部份页面都可以在 PHP 输出一份静态 HTML 之后 Cache 起来。

我使用的是 WP Super Cache 这个插件,大家也可以使用其他的。

把服务器动态生成的静态 HTML 缓存减少服务端开销。我们近期发布的 《中文播客榜》xyzrank.com 直接就是个静态网站。反正数据更新只需要隔一段时间跑一次,没必要接服务端接口。

而且这样好处是永远不会Crash,哈哈哈。

八、What's Next?

本文总结的“老掉牙优化”技术就这么多了。我在六月份做博客优化的时候还没有想到会在七月份发布新站,结果这些东西立马就用上了。

刚刚翻我过去的文章,发现写 Typescript 是2020年,写 Vue 3 + Vite 是2021年,这些东西一开始折腾的时候都是痛并快乐着,现在都成了能用来实现各种想法的基础工具了。

我们播客的监控后台就是使用 ts + Express 做后端, Vue 3 + Vite 做前端实现的,Webpack 也没落下,用在了 xyzrank.com 这个公开项目上。

所以不断学习的感觉很棒,大家也不要觉得现在学一个什么东西可能没啥用,因为指不定哪天信手拈来就能做一个很好玩的东西了。

所以我前段时间在玩的 Golang 什么时候用上呢?🤔

相关链接