昨天看了了美国同事写的页面渲染引擎源代码,很有体会。他们的渲染引擎是线型的,而我的DEV365是层次型的。这区别源自于大家对于渲染的理解不同。
线型渲染认为页面的本质是一串HTML字符流,所有的页面元素就是这个字符流中的一个子串。所有渲染引擎排成一个队列,形成一个“渲染管道”,称之为“PipeLine”。每个引擎负责其中的一部分。对于复杂的页面,引擎会在某时候“沉睡”,当条件满足后被唤醒,然后继续渲染。
层次型渲染认为页面是一个容器,在不同的位置上有不同的页面元素,而这些页面元素也是容器,他们内部包含着更细小的元素。因此页面的渲染就是对页面各元素递归渲染的过程。
以歪酷的主页面为例,可以知道两种渲染方式的不同。简单地看,歪酷的主页面由以下四个部分组成:
页头:显示歪酷的LOGO和相关信息
导航栏:显示菜单和统计信息
正文区:显示最新BLOG摘要
页尾:帮助和联系信息
大体的HTML架构为:
<table>
<tr><td>页头</td></tr>
<tr>
<table>
<tr>
<td>导航栏</td>
<td>正文区</td>
</tr>
</table>
</tr>
<tr>
<td>页尾</td>
</tr>
</table>
线型渲染会有两种做法:
简单型:建立四个引擎,分别渲染下面四个部分。
引擎1负责:<table><tr><td>页头</td></tr><tr>
引擎2负责:<table><tr><td>导航栏</td><td>
引擎3负责:正文区
引擎4负责:</td></tr></table></tr><tr><td>页尾</td></tr></table>
复合型:建立两个引擎,一个渲染外围(假设叫BrandingRander),一个渲染正文区(假设叫ContentRender)。
BrandingRander:<table><tr><td>页头</td></tr><tr><table><tr><td>导航栏</td><td>
ContentRender:正文区
BrandingRander:</td></tr></table></tr><tr><td>页尾</td></tr></table>
当BrandingRender渲染到正文区时,它设定标志,通知ContentRender渲染结束后唤醒它。接着ContentRender开始渲染余下部分。当ContentRender渲染结束后BrandingRander被唤醒,渲染余下的部分。
层次型渲染是这样做的:它认为页头、导航栏、正文区和页尾都是控件(在Dev365中是WebPart,ASP.NET中是WebControl),其他的HTML标记则是简单元素。简单元素直接输出,控件则调用它们的Render方法输出结果。控件也用同样的方法处理内部元素。这个渲染方式其实是和ASP.NET非常相似的。唯一不同的是页面模版和ASP.NET不同,这样做可以达到最高的自由度和输出效率。渲染过程可以看成如下的步骤:
1)输出<table><tr><td>到HttpResponse
2)将HttpResponse作为参数调用页头的Render方法,由其输出自己的内部元素
3)输出</td></tr><tr><table><tr><td>到HttpResponse
4)将HttpResponse作为参数调用导航栏的Render方法,由其输出自己的内部元素
5)输出</td><td>到HttpResponse
6)将HttpResponse作为参数调用正文区的Render方法,由其输出自己的内部元素
7)输出</td></tr></table></tr><tr><td>到HttpResponse
8)将HttpResponse作为参数调用页尾的Render方法,由其输出自己的内部元素
9)输出</td></tr></table>到HttpResponse
10)渲染结束
线型渲染的优点: 结构简单,配置容易,引擎对象是预先创建的,无须再配置,运行速度极快。缺点:不能动态更改配置,难以支持复杂多变的页面,特别地,无法支持用户模版。
层次型渲染的优点:架构清晰,完全基于模版,容易配置和更改,灵活,可扩充性强。缺点:因为递归调用,速度比线型渲染慢。特别地,需要实现很多小控件。
线型渲染比较适合处理内容较多形式复杂的静态页面,而层次渲染比较适合多变的、可用户定义的交互式页面。因此考虑改造线型渲染让它能很好地在Dev365中运作,负责文章和源代码的渲染工作。

