[读书笔记] 高性能网站建设指南

对着背影说爱祢 提交于 2020-03-06 13:44:17

绪言A:前端性能的重要性

性能黄金法则:只有10%~20%的最终用户响应时间花在了下载HTML文档上,其余80%~90%时间花在了下载页面中的所有组件上。

规则1:减少HTTP请求

图片地图

图片地图允许在一个图片上关联多个URL,目标URL的选择取决于用户点击了图片上的哪个位置。

图片地图有两种类型

  • 服务器端图片地图:将用户点击提交到服务端,并向其传递用户点击的x、y坐标。Web应用程序将x、y映射为适当的操作。
  • 客户端图片地图:通过HTML的MAP标签实现。

CSS Sprites

任何支持背景图片的HTML元素都能CSS Sprites,通过background-image和background-position来实现。

内联图片

通过使用data:URL模式可以在Web页面中包含图片但无需任何额外的HTTP请求。

data:[<mediatype>][;base64],<data>

 

由于data:URL是内联在页面中的,在跨越不同页面时不会被缓存

合并脚本和样式表

规则2:使用内容发布网络(CDN)

如果应用程序Web服务器离用户更近,则一个HTTP请求响应时间将缩短。另一方面,如果组件Web服务器离用户更近,则多个HTTP请求的响应时间将缩短。

内容发布网络

内容发布网络是一组分布在多个不同地理位置的Web服务器,用于更加有效地向用户发布内容。

优点:

  • 缩短响应时间
  • CDN包括备份、扩展存储能力和进行缓存等能力,有助于缓和Web流量峰值压力。

缺点:

CDN服务提供商在其所有客户之间共享其Web服务器

无法直接控制组件服务器所带来的特殊麻烦

规则3:添加Expires头

Expires头

浏览器(和代理)使用缓存来减少HTTP请求的数量,并减小HTTP响应的大小,是Web页面加载得更快。

Web服务器使用Expires头来告诉Web客户端它可以使用一个组件的当前副本,直到指定的时间为止。

HTTP简要地称该头为“在这一日期/时间之后,响应被认为是无效的”

Max-Age

HTTP1.1引入了Cache-Control头来客服Expires头的限制。因为Expires头使用一个特定的时间,它要求服务器和客户端的时钟严格同步。另外,过期日期需要经常检查,并且一旦未来这一天到来,还需要在服务器中配置一个新的日期。

Cache-Control使用max-age指令指定组件被缓存多久,它以秒为单位定义了一个更新窗。

可以同时指定Expires和Cache-Control max-age,如果两者同时出现,HTTP规范规定max-age指令将重写Expires头。

如果一个组件没有长久的Expire头,它仍然会存储在浏览器的缓存中。在后续请求中,浏览器会检查缓存并发现组件已经过期。为了提高效率,浏览器会向原始服务器发送一个条件GET请求,如果组件没有改变,原始服务器可以免于发送整个组件,而是发送一个很小的投,告诉浏览器可以使用其缓存的组件。

规则4:压缩组件

压缩是如何工作的

Web客户端可以通过HTTP请求中的Accept-Encoding头来表示对压缩的支持

Accept-Encoding: gzip, deflate

 

如果Web服务器看到请求中有这个头,就会使用客户端列出的方法中的一种来压缩响应,Web服务器通过响应中的Content-Control来通知Web客户端。

Content-Encoding: gzip

 

压缩什么

基于文本的资源如html,js,css,xml都适用于压缩。然而对于图片而言,却不应该对图片进行压缩,因为图片本身是已经被压缩过了,如果再进行gzip压缩,有可能得到的结果是和图片本身大小相差不大或更大,这样就浪费了服务器的CPU资源来做无用功了。

节省

压缩通常能将响应的数据量减少70%。

代理缓存

首先,假设到达代理的是一个来自不支持gzip的浏览器的请求,代理会将请求转发到web服务器,此时web服务器的响应是未经过压缩的,这个响应会把代理服务器缓存起来并发给浏览器。现在,假设到达代理的第二个请求来自一个支持gzip浏览器,请求的是与之前相同的URL,代理会直接使用未经压缩的缓存响应,那么久失去了进行压缩的机会了。考虑更糟糕的情况,第一个请求来自支持gzip的浏览器,第二个请求来自不支持gzip的浏览器,这样第二个请求得到的缓存响应将无法被解码,导致出错。

解决这一问题的方法是在Web服务器的响应中添加Vary头。Web服务器可以告诉代理根据一个或多个头来改变缓存的响应。

Vary: Accept-Encoding

规则5:将样式表放在顶部

将样式表放在文档底部会导致在浏览器中阻止内容逐步呈现。为避免当样式变化时重绘页面中的元素,浏览器会阻塞内容逐步呈现。

将CSS放在顶部

可以通过link标签或者@import规则引入样式。

一个STYLE块可以包含多个@import规则,但是@import规则必须放在其他所有规则之前。使用link标签除了语法简单外,相对于@Import规则,还能带来性能上的收益:@import规则可能会导致白屏,并且使用@import规则会导致组件下载时的无序性。

无样式内容闪烁

如果样式表扔在加载,构建呈现树就是一种浪费,因为在所有样式表加载并解析完毕之前无需绘制任何东西。否则,在其准备好之前显示内容会遇到FOUC(无样式内容的闪烁,Flash of Unstyled Content)问题。

闪烁并不总是发生,它取决于你的浏览器以及如何加载页面,可能会选择白屏,也可能选择承担FOUC风险。

规则6:将脚本放在底部

需要注意,浏览器对每个主机并行下载的组件数量是有限制的。

规则7:避免CSS表达式

规则8:使用外部JavaScript和CSS

纯粹而言,内联快一些。因为外部示例需要承担多个HTTP请求带来的开销。尽管如此,现实中还是外部文件较快。因为JS和CSS文件有机会被浏览器缓存起来。

两全其美的方法:

  • 加载后下载:作为多次页面浏览量中的第一次的主页,我们希望为主页内联JavaScript和CSS,但又能为所有后续页面浏览量提供外部文件。这可以通过在主页加载完成后动态下载外部组件来实现(通过onload事件)。这能够将外部文件放到浏览器中的缓存中以便用户接下来访问其他页面。
  • 动态内联:如果主页服务器知道一个组件是否在浏览器的缓存中,它可以在内联或使用外部文件之间做出最佳的选择。尽管服务器不能查看浏览器缓存中有什么,但可以用cookies做指示器。如果cookies不存在,就内联js和css。如果cookie出现了,则可能外部组件位于浏览器的缓存中,并使用了外部文件。

规则9:减少DNS查找

减少唯一主机的数量会潜在地减少页中并行下载的数量。避免DNS查找降低了响应时间,但减少并行下载可能会增加响应时间。·所以建议主机名至少2个,但不要超过4个。

规则10:精简JavaScript

规则11:避免重定向

规则12:删除重复脚本

规则13:配置ETag

ETag是什么

实体标签(Entity Tag,ETag)是Web服务器和浏览器用于确认缓存组件有效性的一种机制。

条件GET请求

当浏览器缓存的组件过期了(或者用户明确地重新加载了页面),浏览器在重用它之前必须首先检查它是否仍然有效,这称作一个条件GET请求。服务器在检查缓存的组件是否和原始服务器上的组件匹配时有两种方式:

  • 比较最新修改日期
  • 比较实体标签

实体标签

ETag是HTTP1.1中引入。ETag是唯一标识了一个组件的一个特定版本的字符串,唯一的格式约束是该字符串必须用引号引起来。

ETag的加入为验证实体提供了比Last-Modified更灵活机制,如果实体依据User-Agent和Accept-Language头而改变,实体的状态可以反映在ETag中。

如果浏览器必须验证一个组件,它会使用If-None-Match头将ETag传回原始服务器,如果ETag匹配,就会返回304状态码。

ETag带来的问题

通常使用组件的某些属性来构造,这些属性对于特定的、寄宿了网站的服务器来说是唯一的。当浏览器从一台服务器上获取了原始组件,之后,又向另一台不同的服务器发起条件GET请求时,ETag是不会匹配的。

ETag还降低了代理缓存的效率。代理后面用户缓存的ETag经常和代理缓存的ETag不匹配,这导致不必要的请求发送到原始服务器。

如果ETag不匹配,用户就会收到普通的200响应以及组件的所有数据。而对组件进行不必要的重新加载还会影响服务器的性能并增加带宽开销。

If-None-Match比If-Modified-Since具有更高的优先级,如果请求中同时出现了这两个头,原始服务器禁止返回304,除非请求中的条件字段全部一致。

ETag——用还是不用

如果是唯一服务器,使用ETag没有任何问题,但是如果是多台服务器,最好可以自定义ETag:ETag中将只包含大小和时间戳。然而,因为这些都是重复信息,所以最好将ETag完全移除——Last Modified可以提供完全等价的信息。

规则14:使Ajax可缓存

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!