bigPipe 原理分析

PHP在线

共 2297字,需浏览 5分钟

 · 2023-08-01

一、什么是bigPipe?

bigPipe是由facebook提出来的一种动态网页加载技术。它将网页分解成称为pagelets的小块,然后分块传输到浏览器端,进行渲染。它可以有效地提升首屏渲染时间。

为了说清楚什么是bigPipe,我先需要介绍下目前的常规渲染方式,以及可以进行优化的方向。

二、网页首屏加载方案

注:首屏加载方案指的是在服务端就已经吐出页面的方案,也就是说有SSR的方案,那些纯客户端渲染的方案不做比较,因为它们没有首屏要求。

现有的网页首屏加载方案一般会经过以下阶段:

  1. 发送http请求到服务端

  2. 服务端接收并分析请求

  3. 服务端根据请求从存储层获取相关数据,这里可能会比较耗时,比如如果首页涉及多个模块(广告位、推荐、内容列表、用户信息、好友列表等)

  4. 服务端准备好所有内容,拼接成完整的html文档

  5. 发送回客户端

  6. 客户端接收完整的html文档

  7. 构建dom、cssom, 生成render tree,渲染出指定页面

如下图所示:

以上加载方案的缺点是,当2、3、4、5 步在服务端进行的时候,浏览器只能是傻傻地等待,做不了任何事情!


而且第3步并行拉取业务数据在某些场景下(模块多,业务场景复杂),是会占用比较多的时间的。而且只要其中某个模块的数据如果拉取较慢,会拖慢整个首屏的显示。

更糟糕的情况下,某些模块数据相互依赖,导致需要串行拉取数据,那造成的浏览器的等待则会更久。


三、优化方案

以上方案在一些服务端渲染页面中相当常见,不足之处也很明显。

而bigPipe就是针对第3、4步进行优化,让服务端在准备好某个模块的数据后,立马返回给客户端显示,而不必要等待完整的数据和html生成,再发送给客户端。

客户端在接收到某一部分内容后,就可以开始渲染,显示执行(这里可以动态请求需要的css,js 等等)。

如下图,客户端拉取业务数据和客户端渲染页面可以并行。如果某一部分比如广告信息拉取超时,也并不影响其他部分率先渲染显示。

这样,一个完整的页面就可以拆成多个部分,分块渲染,而无需等到拿到完整的页面返回,再渲染。要知道, 如果要等到完整页面返回,在这之前,浏览器只能是一片空白!

四、关键技术和原理

想要实现以上优化方案,可以利用现成的技术,所以有比较好的兼容性。

1.分段传输

bigPipe依赖于分段传输html页面,所以这是实现bigPipe的一个基础。

http1.1

如果在http1.1版本上实现,那需要设置Transfer-Encoding为chunked,也就是分块传输编码。

关于分块传输编码:

分块传输编码允许服务器为动态生成的内容维护HTTP持久连接。在这种情况下,不能使用HTTP Content-Length头来分隔内容和下一个HTTP请求/响应,因为内容大小未知。

分块编码的好处是,在返回客户端前不必生成完整的内容,因为它允许将内容作为分块进行流式处理,并明确地发出内容结尾的信号,从而使连接可用于下一个HTTP请求/响应。

在头部加入 Transfer-Encoding: chunked 之后,就代表这个报文采用了分块编码。这时,报文中的实体需要改为用一系列分块来传输。

每个分块包含十六进制的长度值和数据,长度值独占一行,长度不包括它结尾的 CRLF(\r\n),也不包括分块数据结尾的 CRLF。

最后一个分块长度值必须为 0,对应的分块数据没有内容,表示实体结束。

http 2

如果你使用的是http2,那则无需设置Transfer-Encoding为chunked,因为http2本身就是支持这种分块传输的协议。

2.浏览器渲染原理

说到浏览器渲染,我们可以简单地把它归为五个阶段。(为了方便分析渲染过程,先不考虑有js的情况)

阶段一:

解析html文档,生成节点,构建dom树

阶段二:

在阶段一中,如果遇到css(内嵌在html文档或者外链或者内联样式都一样),则会解析css文档,生成cssom。

阶段三:

阶段一和阶段二都是可以并行的,等到dom和cssom准备好,会进行合并,生成render tree。

阶段四:

根据render tree进行layout。

阶段五:

绘制到显示区域。

整个阶段如下图所示


幸运的是,浏览器并不会等解析完完整的html文档后,才进行layout 和paint

浏览器已经对显示html文档进行了优化,会尽快将解析好的部分呈现给用户。也就是,上图所谓的一次渲染过程,在分块传输的时候,是可以多次进行的。直到接收到</body></html>闭合标签。

五、实践

bigPipe技术的基本原理在上面就已经介绍完了。实践都是基于以上原理而来的。

常规实践是将页面分成各个模块,称之为一个个pagelets,每个pagelets包含自己需要的模板数据,css样式和需要的js。

在传输pagelets之前,先将页面主体layout传输到客户端,先进行渲染,此时,用户已经可以看到页面的主体框架了。

之后,再将服务端处理完的pagelets一个个返回,在客户端渲染。如下图:

浏览 309
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报