从「从输入URL到页面加载」谈及Web性能优化

如何理解 Web 性能优化

事实上就是用户觉得页面加载很快,用户从输入URL(网址)到页面在浏览器上加载出来的时间很短;与之相对的有如服务器性能优化(如网页占的 CPU 少),一定要区分开来。
对于用户众多的网站,节约下的加载时间或能带来可观的收入,这便是前端 Web 性能优化的意义。

从输入 URL 到页面加载发生了什么

一道所有前端耳熟能详的经典面试题,也确实是需要前端去深入研究的东西。下面我会简单介绍其过程,并罗列相关的 Web 优化方案。

0. 缓存

当我们在浏览器上输入网址,浏览器首先会查看是否有缓存,如果之前已经访问过该网站,则会有缓存,那浏览器就不必再向服务器发请求了,用户则能够很快得看到内容。Web 性能优化有极大一部分都是优化缓存,缓存事实上又分为数据库缓存、代理服务器缓存、还有我们熟悉的 CDN 缓存,以及浏览器缓存等,部分内容后文介绍。

1. DNS 查询

DNS 查询就像电话簿,你在浏览器地址栏输入网址,通过 DNS 查询得到域名的真实 IP。

从「从输入URL到页面加载」谈及Web性能优化_第1张图片

DNS查询完成之前,浏览器无法从服务器下载任何数据。

优化方案:减少 DNS 查询

1.1 DNS 缓存

ISP、局域网、操作系统、浏览器等都会有相应的DNS缓存机制。

1.2 减少页面的唯一域名

因为每次 DNS 查询就是查找唯一域名的过程,那么域名越少,DNS 查询就越少,应该尽量将资源放在同一域名。当然这样做又有其他问题,下文详解。

2. TCP 连接

经典的三次握手和四次挥手,不展开赘述。
简单讲讲优化方案:TCP 连接复用(TCP Connection Reuse),在 HTTP 请求头中的 Connection 上加 keep-alive;HTTP/2.0 多路复用等。

3. HTTP 请求及响应

直接讲优化策略

3.1 避免不必要的重定向

最浪费的重定向经常发生、而且很容易被忽略:URL 末尾应该添加/但未添加。比如,访问http://astrology.yahoo.com/astrology将被301重定向到 http://astrology.yahoo.com/astrology/(注意末尾的 /)。如果使用 Apache,可以通过Alias或mod_rewrite或DirectorySlash解决这个问题。

3.2 Cookie

3.2.1减少 Cookie 大小

每次请求都会带上对应的 Cookie,减少 Cookie 大小可以降低其对响应速度的影响:

  • 去除不必要的 Cookie;
  • 尽量压缩 Cookie 大小;
  • 注意设置 Cookie 的 domain 级别,如无必要,不要影响到 sub-domain;
  • 设置合适的过期时间。
3.2.2 静态资源使用无 Cookie 域名

静态资源一般无需使用 Cookie,可以把它们放在使用二级域名或者专门域名的无 Cookie 服务器上,降低 Cookie 传送的造成的流量浪费,提高响应速度。

3.3 添加 Expires 或 Cache-Control 响应头

HTTP/1.1 增加的 Cache-Control,它比 Expires 等好在其设定时间是相对的,避免了用户本地设置时间落后所造成的无法良好缓存的问题等。

  • 静态内容:将 Expires 响应头设置为将来很远的时间,实现「永不过期」策略;
  • 动态内容:设置合适的 Cache-Control 响应头,让浏览器有条件地发起请求。

3.4 配置 Etag

通过如 MD5 等加密算法,设置缓存体的 Etag 配合 3.3 的缓存时间使用,这样 Cache-Control 就可以设置较长时间(max-age 设置个十年半载 ),只要浏览器缓存中资源与源服务器中的资源 Etag 不一致,说明内容更新了,此时再下载新资源;Etag 匹配成功则直接响应 304,不用重复下载了用户自然感觉很快。

3.5 使用 Gzip

使用 Gzip 就是将 HTML、CSS、JS、XML、JSON 等资源进行 Gzip 高效压缩,减少资源体积那么下载就会更快。
Gzip 压缩通常可以减少 70% 的响应大小,对某些文件更可能高达 90%,比 Deflate 更高效。主流 Web 服务器都有相应模块,而且绝大多数浏览器支持 Gzip 解码。
从HTTP/1.1开始,客户端就有了支持压缩的 Accept-Encoding HTTP 请求头。

Accept-Encoding: gzip, deflate

服务器看到这个请求头,它就会用客户端列出的一种方式来压缩响应。web服务器通过 Content-Encoding 响应头来通知客户端。

Content-Encoding: gzip

需要注意的是,已经压缩过的内容如图片和PDF不要使用 Gzip,另外还有文件内容本身就很小,这些资源再使用 Gzip 反而会增加资源下载时间,浪费 CPU 资源,而且还可能增加文件体积。

值得一提

HTTP 请求的另一个优化方案是增加同时请求的数量,浏览器会同时发送多个请求,但是同一域名最多同时发送 4~8 个(不同浏览器不同)请求,那么当资源过多时,可以采用增加域名的方法增加并发量。当然这一方法又与上述 DNS 查询的优化方案矛盾,真正使用的时候就需要权衡。
另外,既然一次只能发的请求有限,就应该将重要的需要优先展示的资源先请求:

3.6 延迟加载(懒加载)

页面初始加载时哪些内容是绝对必需的?不在答案之列的资源都可以延迟加载。比如:

  • 非首屏使用的数据、样式、脚本、图片等;
  • 用户交互时才会显示的内容。

遵循「渐进增强」理念开发的网站:JavaScript用于增强用用户体验,但没有(不支持) JavaScript也能正常工作,完全可以延迟加载JavaScript。

将首屏以外的HTML放在不渲染的元素中,如隐藏的