快速优化 Web 性能的10 个手段
// 每日前端夜话 第580 篇
// 正文共 2700 字
// 预计阅读时间:7 分钟
优化网站的性能需要花费大量的时间,并且如果要根据自己的需求进行优化则花费的时间可能更多。
在本文中,我将向你展示 10 个快速优化 Web 性能的手段,能在 5 分钟内用于你自己的网站。这些捷径对你的代码库或服务器配置几乎没有什么影响。它们简单且容易实现,无需详细了解它们的原理,并且能够对你的性能产生重大影响。
1. 使用文本压缩
使用文本压缩,可以最大程度地减少通过网络传输的字节数。有几种压缩算法。gzip[1] 是最受欢迎的,但 Brotli[2] 是一种更新甚至更好的压缩算法。如果要检查服务器是否支持Brotli,则可以使用 Brotli.pro[3] 工具。
如果你的服务器不支持Brotli,则可以按照以下简单指南进行安装:
-
Nginx on Linux [4] -
Apache [5] -
NodeJs - Express [6]
这是你能够免费得到的第一个优化手段,大多数托管平台或 CDN 默认都会提供压缩。
2. 图像压缩
未压缩的图像是潜在的巨大性能瓶颈。如果不对图像进行压缩,将会消耗很大的带宽。有几种有用的工具可用于快速压缩图像,而不会损失可见质量。我通常使用 Imagemin[7]。它支持多种图像格式,你可以在命令行界面下使用[8]或使用 npm 模块[9]。
imagemin img/* --out-dir=dist/images
你可以将 npm 模块用到 webpack、gulp 或 grunt 等打包程序中。
const imagemin = require('imagemin');
const imageminMozjpeg = require('imagemin-mozjpeg');
(async() => {
const files = await imagemin(
['img/*.jpg'],
{
destination: 'dist/img',
plugins: [
imageminMozjpeg({quality: 60}),
]
}
);
console.log(files);
})();
一般情况下可将 4MB 大小的文件减小到 100kB。可以在 Github中查看演示代码[10]。
单位 | 文件大小,无压缩 | 压缩文件大小 | 文件大小减少百分比 |
---|---|---|---|
Bytes | 4156855 Bytes | 103273 Bytes | -97% |
MB/kB | 4MB | 103 kB | -97% |
3.图片格式
使用现代图像格式可以真正提高性能。WebP 图像比 JPEG 和 PNG 都小,通常小 25%~35%。WebP 得到了浏览器的广泛支持[11]。
我们使用 imagemin npm 包并为其添加 WebP 插件[12]。以下代码可将图像的 WebP 版本输出到 dist 文件夹中。
const imagemin = require('imagemin');
const imageminWebp = require('imagemin-webp');
(async() => {
const files = await imagemin(
['img/*.jpg'],
{
destination: 'dist/img',
plugins: [
imageminWebp({quality: 50})
]
}
);
console.log(files);
})();
再看一下文件大小:
单位 | 文件大小,无压缩 | 压缩文件大小 | 文件大小减少百分比 |
---|---|---|---|
Bytes | 4156855 Bytes | 58940 Bytes | -98% |
MB/kB | 4MB | 59 kB | -98% |
结果表明,与原始图像相比,文件大小减少了 98%,并且与压缩的 JPG 文件相比,WebP 更加明显的压缩了图像。WebP 版本比压缩的 JPEG 版本小 43%。
4. 图像惰性加载
图像惰性加载是一种在以后加载暂时不显示在屏幕上的图像的技术。当解析器遇到图像时立即加载的话会减慢初始页面的加载速度。使用惰性加载,可以加速页面加载过程并稍后加载图像。使用 lazysizes[13] 可以轻松完成此操作。你可以把下面这样的代码:
<img src="image.jpg" alt="">
改为:
<img data-src="image.jpg" class="lazyload" alt="">
lazysizes 库会处理其余的工作,可以使用浏览器进行验证。打开你的站点并找到图像标签。如果该 class 从 lazyload
变成了 lazyloaded
,则意味着它可以正常工作。
5. 缓存你的资源:HTTP 缓存头
缓存是一种可以快速提高网站速度的方法。它减少了老用户的页面加载时间。如果你有权限访问服务器缓存,则用起来非常简单。
你可以使用以下API进行缓存:
-
Cache-Control [14] -
ETag [15] -
Last-Modified [16]
6. 内联关键 CSS:推迟非关键 CSS
CSS 是渲染阻止的。这意味着浏览器必须先下载并处理所有 CSS 文件,然后才能绘制像素。通过内联关键的 CSS,可以大大加快此过程。
你可以按照以下步骤进行操作:
识别关键的 CSS
如果你不知道你的关键CSS是什么,则可以通过 Critcal[17]、CriticalCSS[18] 或 Penthouse[19] 来帮忙。这些库都用来从给定视口中可见的 HTML 文件中提取 CSS。
下面是使用 criticalCSS 的例子。
var criticalcss = require("criticalcss");
var request = require('request');
var path = require( 'path' );
var criticalcss = require("criticalcss");
var fs = require('fs');
var tmpDir = require('os').tmpdir();
var cssUrl = 'https://web.dev/app.css';
var cssPath = path.join( tmpDir, 'app.css' );
request(cssUrl).pipe(fs.createWriteStream(cssPath)).on('close', function() {
criticalcss.getRules(cssPath, function(err, output) {
if (err) {
throw new Error(err);
} else {
criticalcss.findCritical("https://web.dev/", { rules: JSON.parse(output) }, function(err, output) {
if (err) {
throw new Error(err);
} else {
console.log(output);
// 将其保存到文件以进行第 2 步
}
});
}
});
});
内联关键CSS
当 HTML 解析器遇到 style
标签时会立即处理关键的 CSS。
<head>
<style>
body {...}
/* ... 其余的关键CSS */
</style>
</head>
延迟不重要的CSS
非关键的 CSS 不需要立即进行处理。浏览器可以在 onload 事件之后再加载它,使用户不必等待。
<link rel="preload" href="/assets/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/assets/styles.css"></noscript>
7. JavaScript 异步及延迟加载
JavaScript 是 HTML 解析器阻止的。浏览器必须等待 JavaScript 执行才能完成对 HTML 的解析。但是你可以告诉浏览器等待 JavaScript 执行。
异步加载 JavaScript
通过 async
属性,你可以告诉浏览器异步加载脚本。
<script src="app.js" async></script>
Defer JavaScript
defer
属性告诉浏览器在 HTML 解析器完成文档解析之后再运行脚本,但在事件发生之前,将会触发DOMContentLoaded。
<script src="app.js" defer></script>
调整内联脚本的位置
内联脚本会立即执行,浏览器对其进行解析。因此,你可以将它们放在 HTML 的末尾,紧接在 body 标记之前。
8. 使用资源提示加快交付速度。
资源提示[20]能够诉浏览器以后可能加载什么页面。该规范定义了四个原语:
-
preconnect(预连接) -
dns-prefetch(DNS预取) -
prefetch(预取) -
prerender(预渲染)
另外,关于资源提示,我们将 preload[21] 关键字用于 link
属性。
preconnect
下面的代码告诉浏览器你要建立与另一个域的连接。浏览器将为此连接做准备。使用预连接链接标签可以将加载时间缩短 100–500 ms。那么什么时候应该用它呢?直白的说:当你知道在哪里拿东西但不知道该怎么拿。比如哈希样式文件(styles.2f2k1kd.css
)这类的东西。
<link rel="preconnect" href="https://example.com">
dns-prefetch
如果你想告诉浏览器将要建立与非关键域的连接,则可以用 dns-prefetch
进行预连接。这大约能够为你节省 20–120 毫秒。
<link rel="dns-prefetch" href="http://example.com">
prefetch
使用预取,你可以告诉浏览器下载链接标记中所指的整个网站。你可以预取页面或资源。预取在加快网站速度方面非常有用,但是要注意有可能降低网站速度的情况。
低端设备或网速较慢的情况下可能会遇到问题,因为浏览器会一直忙于预取。你可以考虑将预取与自适应加载结合使用,也可以将智能预取与 quicklink[22] 和 Guess.js[23] 结合使用:
<link rel="prefetch" href="index.html" as="document">
<link rel="prefetch" href="main.js" as="script">
<link rel="prefetch" href="main.css" as="style">
<link rel="prefetch" href="font.woff" as="font">
<link rel="prefetch" href="image.webp" as="image">
prerender
<link rel="prerender" href="https://example.com/content/to/prerender">
使用预渲染时,将会先加载内容,然后在后台渲染。当用户导航到预渲染的内容时,内容会立即显示。
preload
借助预加载功能,浏览器会得到引用的资源很重要的提示,应尽快获取。现代浏览器很擅长于对资源进行优先级排序,所以应该只对关键资源使用预加载。可考虑用预连接和预取代替,或者尝试使用 instant.page[24]。
<link rel="preload" as="script" href="critical.js">
9. 使用 Google Fonts
Google Fonts 很不错。他们提供了优质的服务,并且应用广泛。如果你不想自己托管字体,那么 Google 字体是一个很不错的选择。但是你应该注意如何实现它们。Harry Roberts[25] 写了一篇非常出色的文章,内容涉及怎样用 Google Fonts 来为网站加速[26]。强烈建议阅读。
如果你只想知道怎样用,可以通过下面的代码段进行 Google 字体集成,但功劳归功于 Harry。
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=...&display=swap"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=...&display=swap" media="print" onload="this.media='all'"/>
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=...&display=swap"/></noscript>
10. 用 service worker 来缓存你的资源
service worker 是浏览器在后台运行的脚本。缓存是最常用的功能之一,也是你最应该使用的功能。我认为这不是选择问题。通过 service worker 实施缓存,可以使用户与你的站点之间的交互速度更快,而且即使用户断网也可以访问你的网站。
总结
在本文中,我向你介绍 10 个快速优化 Web 性能的手段,能在 5 分钟内用于你自己的网站。你可以在 GitHub 中找到相关资源[27]。
Reference
gzip:https://www.youtube.com/watch?v=whGwm0Lky2s&feature=youtu.be&t=14m11s
[2]Brotli:https://opensource.googleblog.com/2015/09/introducing-brotli-new-compression.html
[3]Brotli.pro:https://www.brotli.pro/
[4]Nginx on Linux:https://computingforgeeks.com/how-to-enable-gzip-brotli-compression-for-nginx-on-linux/
[5]Apache:https://bash-prompt.net/guides/apache-brotoli/
[6]NodeJs - Express:https://web.dev/codelab-text-compression-brotli/
[7]Imagemin:https://github.com/imagemin/imagemin
[8]在命令行界面下使用:https://github.com/imagemin/imagemin-cli
[9]npm 模块:https://www.npmjs.com/package/imagemin
[10]Github中查看演示代码:https://github.com/marcradziwill/web-performance-quick-wins-tutorial
[11]WebP 得到了浏览器的广泛支持:https://caniuse.com/#feat=webp
[12]WebP 插件:https://www.npmjs.com/package/imagemin-webp
[13]lazysizes:https://github.com/aFarkas/lazysizes
[14]Cache-Control:https://developer.mozilla.org/de/docs/Web/HTTP/Headers/Cache-Control#Browser_compatibility
[15]ETag:https://developer.mozilla.org/docs/Web/HTTP/Headers/ETag#Browser_compatibility
[16]Last-Modified:https://developer.mozilla.org/docs/Web/HTTP/Headers/Last-Modified#Browser_compatibility
[17]Critcal:https://github.com/addyosmani/critical
[18]CriticalCSS:https://github.com/filamentgroup/criticalCSS
[19]Penthouse:https://github.com/pocketjoso/penthouse
[20]资源提示:https://www.w3.org/TR/resource-hints/
[21]preload:https://www.w3.org/TR/preload/
[22]quicklink:https://github.com/GoogleChromeLabs/quicklink
[23]Guess.js:https://github.com/guess-js
[24]instant.page:https://instant.page/
[25]Harry Roberts:https://csswizardry.com/
[26]怎样用 Google Fonts 来为网站加速:https://csswizardry.com/2020/05/the-fastest-google-fonts/
[27]GitHub 中找到相关资源:https://github.com/marcradziwill/web-performance-quick-wins-tutorial