以前我们谈性能优化,关键指标是页面 PLC(加载时间)
,简单的定义就是:浏览器中的加载旋转图标停止时间。
而当前,我们构建的不再是一个网页而是一个动态、交互的应用。现在我们来看看网络性能在其优化历程中是如何一步步的提高的。
先聊一聊 "样式在上,脚本在下" 的最佳实践
为什么 "样式在上,脚本在下" 是最佳实践?
要回答这个问题,我们得首先回顾一下浏览器的架构,了解解析、布局和脚本之间如何相互配合在屏幕上绘制出像素来。
浏览器在解析 HTML
文档的基础上构建 DOM
,同时也会 CSS 对象模型,这两个模型共同创建了 渲染树
,之后浏览器就会在屏幕上绘制图形。
优化运行时的渲染和脚本执行固然至关重要,但对于运行在浏览器中的应用来说,迅速而有效的获取网络资源才是第一要义
那么 HTTP 如何有效的获取网络资源?
HTTP1.1 持久连接
在 HTTP1.0 中,每个 TCP 链接开始都有三次握手,要经历一次客户端与服务器间的完整往返。
而在支持持久连接的情况下,就可以避免第二次 TCP 连接时的三次握手、消除另一次 TCP 满启动的往返,节约网络请求。
HTTP1.1 默认启用持久连接,可以在 HTTP 首部添加:
Connection: Keep-Alive
字段来明确要求服务器使用持久连接。
// TODO
使用多个 TCP 连接
持久连接对连接的性能提升巨大,但浏览器在一次请求发起后呆呆的等待服务器的相应却也不是办法。
然后大多数现代浏览器支持了主机打开6个连接,这意味着:
- 客户端可以并行分派最多6个请求;
- 服务器可以并行处理最多6个请求;
这样感觉浏览器可以欢快的加载网络资源了。但是这样的代价、成本却提高了,CPU 占用率提高了,浏览器的开发成本也提高了。
总体来说,这还是没有从根本上解决 HTTP 的限制,是客户端对于web性能提升的一个权宜之计。
为什么限制每个主机最多6个连接,如果客户端超过了最大的连接数,那么后来的所有的客户端请求都会被阻塞。比如,在一个主机上同时打开6个并行下载,再打开第七个请求时,这个请求会挂起,直到前面的请求完成才会执行。这样的情况并不是罕见,比如在应用中,
websocket
、Server sent event
和挂起xhr
,都会占用一个 TCP 连接。
HTTP2.0 多路复用
HTTP2.0 中新的二进制分帧层将 HTTP 消息分解为互不依赖的帧,然后乱序发送,最后在另一端重新组合起来。
有点懵,通过一幅图来了解原理:
HTTP2.0 把消息分解为独立帧,交错发送,然后在另一端按照每个包重新组装(有木有像坐地铁的感觉),就实现了一个连接上有多个请求和响应,从而带来了巨大的性能提升:
- 并行交错的发送请求、发送响应,请求之间、响应之间户不影响
- 一个连接可以并行发起多个请求和响应
- 消除不必要的延迟,从而减少页面加载时间
等等...
参考
Web 性能权威指南
HTTP/2 for a Faster Web
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。