网页分段加载与首屏渲染优化实际上是不同的思路,刚好昨天看了一下BigPipe,想起W3C HTML5中文兴趣小组里百度的闵月提出的首屏渲染优化规范的提案,因此在这里把自己的思路做了一下梳理。

BigPipe能够极大提升站点的性能:在大多数浏览器中,BigPipe都能将用户感受到的延迟时间降低一半。BigPipe设计的内容包括:将页面处理过程分解为8个不同的步骤,其中一些步骤可以并行处理。通过返回如下内容来响应最初的页面请求:

一个未闭合的HTML文档,包含了HTML head标签和body标签的第一部分内容。head标签包含了BigPipe的JavaScript库,用于解释稍后收到的pagelet响应内容。在body标签中,有个模板指定了页面的逻辑结构和pagelets的占位符。

然后创建JSON编码的对象(即pagelets),里面包含了pagelet需要的所有CSS、JavaScript资源、HTML内容以及一些元数据”。

BigPipe页面生成分为以下八个阶段:

  1. 请求解析:Web服务器解析和完整性检查的HTTP请求。
  2. 数据获取:Web服务器从存储层获取数据。
  3. 标记生成:Web服务器生成的响应的HTML标记。
  4. 网络传输:响应从Web服务器传送到浏览器。
  5. CSS的下载:浏览器下载网页的CSS的要求。
  6. DOM树结构和CSS样式:浏览器构造的DOM文档树,然后应用它的CSS规则。
  7. JavaScript中下载:浏览器下载网页中JavaScript引用的资源。
  8. JavaScript执行:浏览器的网页执行JavaScript代码。

但这整个流程只是一个pagelet的完整流程,BigPipe 打破了原有的顺序执行,将页面分成不同的pagelet,如此一来,所有的pagelet的执行时间累加起来还是原有的时间。但是通过叠加不同pagelet的不同阶段的执行时间,使总的运行时间大大减少。

当浏览器访问服务器时,服务器接受请求并对其进行检查。如果请求有效,服务器端不做任何的查询,而是立刻返回一个 http request给浏览器,内容是一段HTML代码,包括html标签和标签的一部分。标签包括BigPipe 的js文件和css文件,这个js文件用来解析后面接收的http response,因为后面传输的内容都为js脚本。未封闭的标签中,是显示页面的逻辑结构和pagelet的占位符的模板。

将这个response返回给浏览器后,服务器开始对每个pagelet的内容进行查询,加载,生成。当一个pagelet的内容生成好,立刻调用flush()函数,将其返回给客户端,传输的数据是以JSON格式的,包括这个pagelet需要的CSS和JS,以及HTML 内容和一些元数据。

虽然每个pagelet都有要加载的js文件,但是所有的js文件都是在最后加载,这样有利于加快页面加载速度。客户端,当通过调用”onPageletArrive(json)”函数,第一次影响传输的js脚本中 的函数解析了传入的JSON数据,接着下载需要的CSS,然后把HTML内容显示到响应的DIV 标签位置上。多个pagelets的CSS文件可以同时下载,CSS下载完成的pagelet先显示。

在BigPipe中,js被给予了比CSS 和content更低的优先级。这样,只有当所有的pagelets都显示了,BigPipe才开始去下载JS 文件。所有的js文件都下载完成后,Pagelets的js初始化代码开始执行,按照下载完成时间的先后顺序。在这个高度并行的系统中,几个的pagelet所要执行的不同的阶段可以同时执行。例如,浏览器可以给两个pagelets下载CSS资源,同时浏览器可以渲染另外一个pagelet的内容,同时服务器仍然在为另一个pagelet生成HTML源码。从用户的角度看来,页面时逐步呈现的。初始的页面显示的更快,可以有效减短用户感觉到的延迟。

理想情况下,服务器端的实现是并行处理不同的pagelet的内容,这样可以提升性能。服务器并发处理多个pagelet的内容时,一个pagelet内容生成好了,立刻将其flush 给浏览器。但是PHP是不支持线程,所以服务器无法利用多线程的概念去并发的加载多个pagelet的内容。对于小型网站来说,使用串行的加载pagelet的内容就已经可以达到优化的要求了。对于大型网站,为了达到更快的速度,服务器端可以选择并发地处理不同的pagelet的内容。

BigPipe使用js加载页面,随之而来影响的可能影响禁用了浏览器js功能的用户,以及对SEO造成影响,这时候就需要服务器端检测user-agent和客户端是否支持js脚本,如果是搜索引擎蜘蛛或者客户端不支持js脚本,那就维持原有的模式。

前文提到的首屏渲染优化,是为了加快移动端用户实际感知到首屏内容展现的速度(虽然只是一段提案),摘录一段它的介绍:

首屏渲染优化规范用于加速移动设备上首屏内容的绘制可见速度。

在web页面代码解析(parse)后,还需要经过布局(layout)与绘制(paint)阶段,才能在屏幕上展示给用户。移动设备屏幕很小,通常很短的代码就能够充满这个屏幕,而这部分内容就是用户首先实际感知到的内容区域。

当一个页面代码由A、B两段组成,代码A能够表示首屏的所有内容,当A完成web内容解析(parse)后,并不能立刻完成布局(layout)与绘制上屏操作(paint)。内核从parse状态转化成layout状态,存在若干触发条件,它们包括了解析的token数目,解析的时间以及延迟(delay)时间。内核从layout状态转化成paint状态,同样存在若干必要条件,这些条件使得内核无法提早退出layout流程,进入实际上屏绘制阶段。所有这些限制条件并没有充分考虑到手机首屏内容的大小,以及实际用户感知内容展现的重要优先级。在复杂的移动网络环境下这种限制对浏览速度的影响更大。

通过定义首屏渲染优化规范,web开发者可以指定浏览器进行合适的首屏内容提前绘制(内核可自行判断首屏位置或是由开发者指定首屏位置),从而加快首屏展现速度,显著缩短用户首次看见非白屏页面时间。

参考文章