使用Transfer-Encoding:chunked头信息

大多数的站点相应用户请求时发送的HTTP Headers中包含Content-Length头.此头信息定义在HTTP1.0协议RFC 1945 10.4章节中.该信息是用来告知用户代理,通常意义上就是浏览器,服务端发送的文档内容长度.浏览器接受到此信息后,接收完Content-Length中定义的长度字节后开始解析页面.如果服务端有部分数据延迟发送,那么浏览器就会白屏.这样导致比较糟糕的用户体验.

解决方法在HTTP1.1协议.RFC2616中14.41章节中定义的Transfer-Encoding:chunked的头信息.chunked编码定义在3.6.1中.根据此定义浏览器不需要等到内容字节全部下载完成,只要接收到一个chunked块就可解析页面.并且可以下载html中定义的页面内容,包括js,css,image等.采用chunked编码有两种选择,一种是设定Server的IO buffer长度让Server自动flush buffer中的内容,另一种是手动调用IO中的flush函数。

不同的语言IO中都有flush功能:

  • php:    ob_flush(); flush();
  • perl:   STDOUT->autoflush(1);
  • java:  out.flush();
  • python:  sys.stdout.flush()
  • ruby:  stdout.flush

从下面两张图中可以看出采用HTTP1.1的Transfer-Encoding:chunked,并且把IO的buffer flush下来,以便浏览器更早的下载页面配套资源.

normal response

normal response

flush response

flush response

video 对比

Normal response

Flush response

采用flush功能不单单能够让浏览器更早地下载页面配套资源,而且能够更好的提升用户体验。和上图一样服务器因为某种原因延迟了发送页面文档导致3秒的延迟,那么采用Content-Length头信息的页面将会白屏3秒,用户不知道是他本机的网络问题还是服务器的问题。而采用Transfer-Encoding:chunked的页面会显示页面的头部信息。用户知道他浏览器已经和正等待服务器取得联系,等待服务器发送更多的内容。

explaining rightmost selector is key selector

从Safari,WebKit的架构师和Mozilla中XUL项目的style的实现者David Hyatt发布的一片文章中Writing Efficient CSS for use in the Mozilla UI,我们学习到:
  1. 避免非ID,class,tag的选择器,包括:通用的选择,包括子选择器,同胞选择器,后代选择器,属性选择器
  2. 不要限定ID选择器和class选择器
  3. 尝试使用简单的选择器代替复杂的选择器
  4. 避免后代选择器
  5. 避免在左边第一个选择器后使用tag选择器
  6. 当心使用子选择器,当然也包括后代选择器
  7. 依赖规则的继承
文中还提到key selector是最右边的选择器,那么为什么关键选择器是右边的选择器呢?我们可以从对Style实现的思考中一窥奥秘:

假设我们的选择器是:#p  a > img,那么存成链表结构的话会有两种可能:#p->a->img和img->a->#p。如果我们是使用#p->a->img的话,那么我们选择到id为p的节点,然后再从这个节点遍历全部的子节点找到节点为a并且其子节点为img的节点。但是这种选择的话还有一个问题:如果还有css rule是.cl img,那么我们还是要做一次节点遍历。而我通过统计一般站点平均一个页面的css rules是一千多个,即基本上拥有一个一千多个rules的集合。当我们要对一个标签为img的节点进行渲染得时候,我们必须找到其rules,并对这些rules进行cascading和计算这个节点的实际的渲染值。我们则必须要对一千多个rules的集合进行遍历,并对关键选择器节点的子树进行遍历,才能找到我们什么样的rules的集合能应用于这个节点。这是一个很不好实现手段,性能将是这种实现的瓶颈(实际实现有优化空间,不会如上所述,这里只是就举例说明。)。再来看看最右边的关键选择器的实现。使用img->a->#p时,当一个节点进来匹配首先我们能够从rules的集合中过滤掉一些rules,然后再通过对剩余的rules集合进行文档当前节点的父节点遍历检查是否匹配rule。即可得到最终的rules的集合,然后对这些rules进行cascading和计算这个节点的实际的渲染值。

从性能考虑的话key selector是最右边的选择器是最佳选择。

Hello world!

Hello world!开始写blog了,记录工作生活点滴。