不管是通过网络传输而来的,还是缓存在本地磁盘的,资源最初都是以字节(1)流的形式存在的。将字节流转变为可视化的页面,是浏览器最核心的功能。
在浏览器中,能够将 HTML、CSS、Javascript 以及其他资源( 图片、视频等 )转换成可视化页面的模块,叫渲染引擎。
(1)字节( Byte )是二进制数据的单位,按照 UTF-8 编码标准,一个英文字母等于一个字节,一个汉字等于三个字节。
渲染引擎的主要功能
- 调用 HTML 编译器
- 调用 CSS 编译器
- 调用 Javascript 编译器
- 调用其他资源( 图片、视频等 )解码器
- 布局
- 绘图
多线程
渲染引擎的主线程是 GUI 渲染线程,负责布局和绘图,而其他资源的数据都交给不同线程去完成,比如,网页交给 HTML 编译器转变成一系列的词语,Javascript 代码调用 Javascript 引擎编译和执行。
主流渲染引擎
HTML 编译器目前,主流的渲染引擎包括 Trident( IE 浏览器 )、Gecko( 火狐浏览器 )和 WebKit( Chrome 浏览器、Safari 浏览器、Android 浏览器 )。
HTML 编译器的工作就是将网络或者本地磁盘获取的 HTML 网页和资源从字节流编译成 DOM 树结构。这一过程大致可以理解成下图所述的步骤:
解码:
HTML 编译器首先要做的事情是如何正确地解码字节流。服务器一般会通过响应头里的 Content-Type 字段,告知编译器字符的编码格式。
例子:
//text/html 表示文件格式 //charset=UTF-8 表示字符编码格式 Content-Type: text/html; charset=UTF-8
如果服务器没有返回 Content-Type 的信息,编译器会自动匹配 HTML 文档中设置的编码格式( 写在 标签中 )。通常,编译器会等待500ms或1024字节,以提高匹配到编码格式的可能性。因此,HTML 文档中的字符编码声明要出现在前1024个字节中。
例子:
如果以上算法都不能确定解码方式,编译器会调用默认字符编码。默认编码通常取决于用户的所在区域,或用户网页常用的语言,例如 GB18030
是默认的汉字编码标准。
词法分析
这个过程会将字符流分解成有意义的词法单元( token )。
例子:
hello
如果我们从" 最小且有意义 "的单元来拆分这段代码( 字符流 ),可以把它依次拆分成如下这样:
:"开始标签"的结束 hello:文本
: 结束标签
那么,渲染引擎是如何实现拆分的呢?大多数编程语言的词法分析都是通过" 状态机 "来实现的。
所谓状态机,简单说,就是把每一个流入的字符都标记上状态,并根据当前字符状态,标记下一个字符的状态,然后把相关字符合并起来,返回有意义的词语。
例子中,初始状态为" 数据状态 “;编译器获得字符 < ,状态改为” 标签打开状态 “;之后获得字符 p ,状态改为” 开始标签状态 “;接下来编译器一直读,当读到空格时,状态恢复到” 数据状态 ",并返回完整的词
语法分析
这个过程是将词法单元流转换成 DOM 节点,与此同时,构建一个由节点逐级嵌套的 DOM 树。经过语法分析,HTML 文档变成了一组允许 Javascript 访问和交互的对象。
语法分析主要通过栈( 后进先出 )和插入模式来实现。这些节点会在接收到相应的" 开始标签状态 “的词时创建并入栈,然后在接收到” 结束标签状态 "的词时出栈。下面举例说明:
例子:
hello lover



