Fork me on GitHub
秋染蒹葭

前端性能优化之二:网络性能优化

网络优化是大有可为的,比如使用缓存、http传输压缩、减少http请求数目,以及dns发散与dns收敛的不同作用等等。

使用缓存

浏览器在第一次访问页面时向服务器请求资源,并缓存起来,下次再访问时会判断在缓存中是否已有该资源且有没有更新过,如果已有该资源且未更新过,则直接从浏览器缓存中读取。关于缓存可看另外一篇文章《http协议详解之一:缓存(熟悉的304)》

已缓存资源不再发起http请求,即HTTP的Expires和Cache-Control。对一个网站而言,CSS、JavaScript、图片等静态资源更新的频率都比较低,而这些文件又几乎是每次HTTP请求都需要的,如果将这些文件缓存在浏览器中,可以极好的改善性能。通过设置http头中的cache-control和expires的属性,可设定浏览器缓存,将静态内容设为永不过期,或者很长时间后才过期。

http传输压缩

我们在将css,js,图片等资源部署是会将文件压缩,比如js文件和css,会将空格,注释等信息完全删除掉。对http传输的压缩和这些压缩的目的相同,都是为了减少文件下载的时间,但是两者相互没有影响。

从HTTP1.1开始,客户端可以通过Accept-Encoding头来声明浏览器支持的压缩方式,服务端通过content-Encoding来启用压缩,配置压缩的文件类型,压缩方式。当客户端的请求到达服务器,服务器对资源进行压缩后,返回给客户端,客户端按照相应的方式进行解析。

1
2
3
4
5
客户端(HTTP请求头)——accept-encoding: gzip, deflate, sdch, br
服务器(HTTP响应头)——content-encoding:gzip
文件传输前的大小——通过属性查看
文件传输过程中的大小——通过Network中的Size查看

gzip是GUNzip的缩写,使用无损压缩,压缩效果最佳,已经成为使用最为普遍、支持的浏览器最多的数据压缩格式。天猫、淘宝、京东、苏宁、腾讯、百度等大型网站都使用gzip压缩方式。

客户端不用做任何配置,在服务端配置即可,不同服务器的配置方法也不尽相同。这种配置的好处是减少HTTP响应时间,提升传输效率,当然也有也负面影响:压缩过程占用服务器额外的CPU周期,客户端也要对压缩文件进行解压缩,这也需要占用部分时间。随着硬件性能不断提高,上述问题正在不断弱化,国内外大型网站都对HTTP传输进行压缩。

减少http的请求数

这个应该已经不是什么大的问题了

  • 图片地图允许在一个图片上关联多个URL,目标URL取决于用户单击的图片上的位置。
  • CSS Sprites,CSS精灵,合并图片,通过指定CSS的backgroud-image和backgroud-position来显示元素。
  • 合并JS脚本和CSS样式表
  • 在用户不带缓存访问页面的时候,内联所有的js和css的效率更快,原因是外置js和css带来额外的http请求开销,1个http请求相对于3个http请求要更快一些。
    其实,使用外部JS和CSS文件会产生更快的访问速度,这是由于外部JS和CSS文件能被浏览器缓存,当下次再请求相同的JS和CSS时,浏览器将不会再发出HTTP请求,而是使用缓存的JS和CSS文件,减少了HTTP请求数。

CDN内容分发网络

CDN是一组分布在多个不同地理位置的Web服务器,用于更加有效地向用户发布内容,在优化性能时,会根据距离的远近来选择。

CDN将网站的资源发布到离用户最近的网络边缘,用户可以就近取得资源内容。

CDN通常部署静态内容:JavaScript脚本、CSS样式表、图片、图标、Flash等,不包括html页面。

浏览器是根据域(Domain)来缓存内容资源的,只要域(Domain)不一样,那么即使是同一个资源,也需要重复下载,且使用同样的方式缓存起来,这需要需要占用带宽和本地缓存空间。

如何优化

将静态资源缓存到离用户很近的相同网络运营商的CDN节点上
如果服务器离用户更近,则HTTP请求和响应时间将缩短。

不同地区的用户访问同一个域名能得到不同CDN节点的IP地址,这要依赖于CDN服务商提供的智能DNS服务,浏览器发起域名查询时,智能DNS服务会根据用户IP计算并返回离它最近的相同网络运营商的CDN节点IP。

通过智能DNS服务获取最近的相同网络运营商的CDN节点IP后,不同地区的用户会向离自己最近的相同网络运营商的CDN节点发起请求,当请求达到CDN节点后,节点会判断自己的内容缓存是否有效,一个地区内只要有一个用户先加载资源,就会在CDN中建立缓存,该地区的其他后续用户都能直接读取缓存数据。

加载静态资源使用与页面不同的域名(不是用独立的二级或三级域名,而是用独立的一级域名)
静态资源和主页面不同域,加载静态资源的HTTP请求就不会带上主页面中的cookie等数据,减少了数据传输量,节省流量,提升上传效率。

cookie优化

cookie存储在客户端,伴随着HTTP请求在浏览器和服务器之间传递。除了key-value外,cookie还有max-age,path,domain和httponly属性。

HTTP 压缩(Gzip)

开启 Gzip具体的做法非常简单,只需要你在你的 request headers 中加上这么一句:

1
accept-encoding:gzip

先说一下和前端关系密切的http压缩:

HTTP 压缩是一种内置到网页服务器和网页客户端中以改进传输速度和带宽利用率的方式。在使用 HTTP 压缩的情况下,HTTP 数据在从服务器发送前就已压缩:兼容的浏览器将在下载所需的格式前宣告支持何种方法给服务器;不支持压缩方法的浏览器将下载未经压缩的数据。最常见的压缩方案包括 Gzip 和 Deflate。

HTTP 压缩就是以缩小体积为目的,对 HTTP 内容进行重新编码的过程。Gzip 的内核就是 Deflate,目前我们压缩文件用得最多的就是 Gzip。可以说,Gzip 就是 HTTP 压缩的经典例题。

该不该用 Gzip

Gzip 是高效的,压缩后通常能帮我们减少响应 70% 左右的大小。但它并非万能。Gzip 并不保证针对每一个文件的压缩都会使其变小。

Gzip 压缩背后的原理,是在一个文本文件中找出一些重复出现的字符串、临时替换它们,从而使整个文件变小。根据这个原理,文件中代码的重复率越高,那么压缩的效率就越高,使用 Gzip 的收益也就越大。反之亦然。

webpack 的 Gzip 和服务端的 Gzip

一般来说,Gzip 压缩是服务器的活儿:服务器了解到我们这边有一个 Gzip 压缩的需求,它会启动自己的 CPU 去为我们完成这个任务。而压缩文件这个过程本身是需要耗费时间的,大家可以理解为我们以服务器压缩的时间开销和 CPU 开销(以及浏览器解析压缩文件的开销)为代价,省下了一些传输过程中的时间开销。

既然存在着这样的交换,那么就要求我们学会权衡。服务器的 CPU 性能不是无限的,如果存在大量的压缩需求,服务器也扛不住的。服务器一旦因此慢下来了,用户还是要等。Webpack 中 Gzip 压缩操作的存在,事实上就是为了在构建过程中去做一部分服务器的工作,为服务器分压。

因此,这两个地方的 Gzip 压缩,谁也不能替代谁。它们必须和平共处,好好合作。作为开发者,我们也应该结合业务压力的实际强度情况,去做好这其中的权衡。

图片优化

《高性能网站建设指南》的作者 Steve Souders 曾在 2013 年的一篇 博客 中提到:

图片是用户可以直观看到的。他们并不会关注 JS 和 CSS。确实,JS 和 CSS 会影响图片内容的展示,尤其是会影响图片的展示方式(比如图片轮播,CSS 背景图和媒体查询)。但是我认为 JS 和 CSS 只是展示图片的方式。在页面加载的过程中,应当先让图片和文字先展示,而不是试图保证 JS 和 CSS 更快下载完成。

雅虎军规和 Google 官方的最佳实践也都将图片优化列为前端性能优化必不可少的环节——图片优化的优先级可见一斑。

按照 HTTP-Archive网站的统计,不管是资源总量还是图片体积,都在往越来越轻量的方向演化。这是一种值得肯定的进步。

不同业务场景下的图片方案选型

时下应用较为广泛的 Web 图片格式有 JPEG/JPG、PNG、WebP、Base64、SVG 等,这些格式都是很有故事的,值得我们好好研究一把。此外,老生常谈的雪碧图(CSS Sprites)至今也仍在一线的前端应用中发光发热。

JPEG/JPG,

有损压缩、体积小、加载快、不支持透明。JPG 最大的特点是有损压缩。这种高效的压缩算法使它成为了一种非常轻巧的图片格式。另一方面,即使被称为“有损”压缩,JPG的压缩方式仍然是一种高质量的压缩方式:当我们把图片体积压缩至原有体积的 50% 以下时,JPG 仍然可以保持住 60% 的品质。

JPG 适用于呈现色彩丰富的图片,在我们日常开发中,JPG 图片经常作为大的背景图、轮播图或 Banner 图出现。使用 JPG 呈现大图,既可以保住图片的质量,又不会带来令人头疼的图片体积,是当下比较推崇的一种方案。

有损压缩在上文所展示的轮播图上确实很难露出马脚,但当它处理矢量图形和 Logo 等线条感较强、颜色对比强烈的图像时,人为压缩导致的图片模糊会相当明显。此外,JPEG 图像不支持透明度处理,透明图片需要召唤 PNG 来呈现。

PNG-8 与 PNG-24

无损压缩、质量高、体积大、支持透明。PNG(可移植网络图形格式)是一种无损压缩的高保真的图片格式。8 和 24,这里都是二进制数的位数。按照我们前置知识里提到的对应关系,8 位的 PNG 最多支持 256 种颜色,而 24 位的可以呈现约 1600 万种颜色。PNG 图片具有比 JPG 更强的色彩表现力,对线条的处理更加细腻,对透明度有良好的支持。它弥补了上文我们提到的 JPG 的局限性,唯一的 BUG 就是体积太大

什么时候用 PNG-8,什么时候用 PNG-24,这是一个问题。

理论上来说,当你追求最佳的显示效果、并且不在意文件体积大小时,是推荐使用 PNG-24 的。

但实践当中,为了规避体积的问题,我们一般不用PNG去处理较复杂的图像。当我们遇到适合 PNG 的场景时,也会优先选择更为小巧的 PNG-8。好的做法是把图片先按照这两种格式分别输出,看 PNG-8 输出的结果是否会带来肉眼可见的质量损耗,并且确认这种损耗是否在我们(尤其是你的 UI 设计师)可接受的范围内,基于对比的结果去做判断。

考虑到 PNG 在处理线条和颜色对比度方面的优势,我们主要用它来呈现小的 Logo、颜色简单且对比强烈的图片或背景等。

SVG

文本文件、体积小、不失真、兼容性好,SVG(可缩放矢量图形)是一种基于 XML 语法的图像格式。它和本文提及的其它图片种类有着本质的不同:SVG 对图像的处理不是基于像素点,而是是基于对图像的形状描述。

和性能关系最密切的一点就是:SVG 与 PNG 和 JPG 相比,文件体积更小,可压缩性更强。当然,作为矢量图,它最显著的优势还是在于图片可无限放大而不失真这一点上。这使得 SVG 即使是被放到视网膜屏幕上,也可以一如既往地展现出较好的成像品质——1 张 SVG 足以适配 n 种分辨率。

SVG 的局限性主要有两个方面,一方面是它的渲染成本比较高,这点对性能来说是很不利的。另一方面,SVG 存在着其它图片格式所没有的学习成本(它是可编程的)。

SVG 是文本文件,开发中我们可以将 SVG 写入 HTML,也可以将 SVG 写入独立文件后引入 HTML。

在实际开发中,我们更多用到的是后者。很多情况下设计师会给到我们 SVG 文件,就算没有设计师,我们还有非常好用的 在线矢量图形库。对于矢量图,我们无须深究过多,只需要对其核心特性有所掌握、日后在应用时做到有迹可循即可。

Base64

文本文件、依赖编码、小图标解决方案,Base64 并非一种图片格式,而是一种编码方式。Base64 和雪碧图一样,是作为小图标解决方案而存在的。和雪碧图一样,Base64 图片的出现,也是为了减少加载网页图片时对服务器的请求次数,从而提升网页性能。Base64 是作为雪碧图的补充而存在的。

Base64 是一种用于传输 8Bit 字节码的编码方式,通过对图片进行 Base64 编码,我们可以直接将编码结果写入 HTML 或者写入 CSS,从而减少 HTTP 请求的次数。

既然 Base64 这么棒,我们何不把大图也换成 Base64 呢?
这是因为,Base64 编码后,图片大小会膨胀为原文件的 4/3(这是由 Base64 的编码原理决定的)。如果我们把大图也编码到 HTML 或 CSS 文件中,后者的体积会明显增加,即便我们减少了 HTTP 请求,也无法弥补这庞大的体积带来的性能开销,得不偿失。

在传输非常小的图片的时候,Base64 带来的文件体积膨胀、以及浏览器解析 Base64 的时间开销,与它节省掉的 HTTP 请求开销相比,可以忽略不计,这时候才能真正体现出它在性能方面的优势。

因此,Base64 并非万全之策,我们往往在一张图片满足以下条件时会对它应用 Base64 编码:

  • 图片的实际尺寸很小(大家可以观察一下掘金页面的 Base64 图,几乎没有超过 2kb 的)
  • 图片无法以雪碧图的形式与其它小图结合(合成雪碧图仍是主要的减少 HTTP 请求的途径,Base64 是雪碧图的补充)
  • 图片的更新频率非常低(不需我们重复编码和修改文件内容,维护成本较低)

推荐的是利用 webpack 来进行 Base64 的编码——webpack 的 url-loader 非常聪明,它除了具备基本的 Base64 转码能力,还可以结合文件大小,帮我们判断图片是否有必要进行 Base64 编码。

WebP

年轻的全能型选手,WebP 是今天在座各类图片格式中最年轻的一位,它于 2010 年被提出, 是 Google 专为 Web 开发的一种旨在加快图片加载速度的图片格式,它支持有损压缩和无损压缩。

WebP 像 JPEG 一样对细节丰富的图片信手拈来,像 PNG 一样支持透明,像 GIF 一样可以显示动态图片——它集多种图片文件格式的优点于一身。WebP 的官方介绍对这一点有着更权威的阐述:

与 PNG 相比,WebP 无损图像的尺寸缩小了 26%。在等效的 SSIM 质量指数下,WebP 有损图像比同类 JPEG 图像小 25-34%。 无损 WebP 支持透明度(也称为 alpha 通道),仅需 22% 的额外字节。对于有损 RGB 压缩可接受的情况,有损 WebP 也支持透明度,与 PNG 相比,通常提供 3 倍的文件大小。

WebP 纵有千般好,但它毕竟太年轻。我们知道,任何新生事物,都逃不开兼容性的大坑。此外,WebP 还会增加服务器的负担——和编码 JPG 文件相比,编码同样质量的 WebP 文件会占用更多的计算资源。

现在限制我们使用 WebP 的最大问题不是“这个图片是否适合用 WebP 呈现”的问题,而是“浏览器是否允许 WebP”的问题,即我们上文谈到的兼容性问题。

WebP 格式的局限性确实比较明显,如果决定使用 WebP,兼容性处理是必不可少的。

小结

图片是电商平台的重要资源,甚至有人说“做电商就是做图片”。淘宝和京东,都是流量巨大、技术成熟的站点,它们在性能优化方面起步早、成效好,很多方面说是教科书般的案例也不为过。当我们不知道怎么切入的时候,或者说当我们面对一个具体的问题无从下手的时候,除了翻阅手中的书本(很可能是已经过时的)和网络上收藏的文章(也许没那么权威),现在是不是又多了“打开那些优秀的网站看一看”这条路可以走了呢?

参考资料
浅谈前端性能优化(六)——CDN内容分发网络
前端性能优化-gzip压缩
《高性能网站建设指南》作者Steve Souders
HTTP-Archive

本文标题:前端性能优化之二:网络性能优化

文章作者:zhyjor

发布时间:2018年02月06日 - 12:02

最后更新:2023年10月11日 - 02:10

原始链接:https://zhyjor.github.io/2018/02/06/前端性能优化之二:网络性能优化/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

🐶 您的支持将鼓励我继续创作 🐶

热评文章