最近看了< webkit技术内幕 >,虽然并不能完全看懂,但是对浏览器的渲染机制也算是有了一个比较完整的认识。

我们从浏览器地址栏输入网址开始到web页面被完整的呈现在眼前,大概的经过了这样一个过程:网址被DNS解析为IP地址 -> 通过IP地址建立TCP连接 -> 发送HTTP请求 -> 服务器处理请求并返回响应 ->  浏览器解析渲染页面 -> 断开TCP连接

可是浏览器是怎么去解析渲染页面的呢?这里就要了解浏览器的内核,也就是浏览器的渲染引擎(严格来说应该是渲染引擎 + Javascript引擎),页面的渲染工作便是由渲染引擎完成的。需要注意浏览器和浏览器内核是不同的概念,浏览器指的是 Chrome、Firefox 等,而浏览器内核则是 Blink、Gecko 等,浏览器内核只负责渲染,GUI 及网络连接等跨平台工作则是浏览器实现的。主流的渲染引擎包括Trident、Gecko、Webkit,它们分别是IE、火狐和Chrome的内核(2013年,Google宣布了Blink内核,它其实是从Webkit复制出去的)。一般渲染引擎主要包括HTML解释器、CSS解释器、Javascript引擎、布局、绘图等模块。当然这些模块还依赖很多其他的基础模块。

我们先简单的了解一下渲染引擎各个主模块所做的工作(以下所有的介绍以 webkit 为介绍对象)

HTML解释器 :HTML解释器的工作就是将网络或者本地磁盘获取到的HTML网页和资源从字节流解释成DOM树的结构(首先是字节流,经过解码之后是字符流,然后通过词法分析器会被解释成词语(TOKENS),经过语法分析器构建成节点,最后这些节点被组建成一颗DOM树)

CSS解释器 :CSS字符串被CSS解释器处理后变成渲染引擎的内部规则表示。(样式规则建立完成之后,webkit会保存规则结果,当DOM的节点建立之后,webkit会为可视化节点选择合适的样式信息,即作样式规则匹配)

Javascript引擎 :将Javascript代码处理并执行,一个Javascript引擎可以包括以下几个部分 ->

  编译器 -> 主要工作是将源代码编译成抽象语法树,在某些引擎中还包括将抽象语法树转换为字节码(JavascriptCore 引擎)。

  解释器  -> 在某些引擎中,解释器主要是接收字节码,解释执行字节码,同时也依赖垃圾回收机制等。

  JIT工具 -> 将字节码或者抽象语法树转换为本地代码 (V8 引擎)

  垃圾回收器和分析工具

布局 :计算RenderObject对象的位置、大小等信息

绘图 :将构建好的渲染内部表示模型使用图形库绘制出来

页面的最终渲染便是上述模块综合处理的结果。根据数据的流向,这里可以把渲染的过程分为三个阶段,第一个阶段是从网页的url到构建完dom树,第二个阶段是从dom树到构建完webkit的绘图上下文,第三个阶段是从绘图上下文到生成最后的图像。

上图描述的是网页 url 到构建完DOM树的整个过程,数字表示的是基本顺序,不过也不是严格一致,因为这个过程可能会有所重复或者交叉。

具体的过程如下:

1 当用户输入网页url的时候,webkit调用资源加载器加载对应的网页。

2 加载器依赖网络模块建立连接,发生请求并接收响应。

3 webkit接收到各种网页或者资源的数据,其中某些资源可能是同步或者异步的方式获取的。

4 网页被交给HTML解释器解释成一系列词语(Token)

5 解释器根据词语构建节点(Node),形成DOM树。

6 如果节点是Javascript代码的话,调用Javascript引擎解释执行。

7 Javascript代码可能会修改DOM树的结构。

8 如果有节点需要依赖其他的资源,比如图片、css、视频等,调用资源加载器来加载它们,不过这个过程是异步的,不会阻碍当前DOM树的继续构建。如果是Javascript资源 url (没有标记异步方式),则需要停止当前DOM树的构建,直到Javascript的资源被加载并被Javascript引擎解释执行后才继续DOM树的创建。

在上述过程当中,网页在加载和被渲染完毕的这一段过程会相继发出“DOMContent”事件和“onload”事件,分别表示DOM树构建完毕以及DOM树及其所有依赖的资源都加载完毕。一般来说“DOMContent”事件会先于“onload”事件发生。

接下来就是Webkit借助 css 和 dom 树构建RenderObject树直到绘图上下文。

1 css文件被css解释器解释为内部表示结果

2 css解释器完成工作之后在dom树上附加解释后的样式信息,这就是RenderObject树

3 RenderObject节点被创建的同时,webkit会根据网页的层次结构创建RenderLayer树,同时创建一个虚拟的绘图上下文。

RenderObject树的建立并不会导致DOM树被销毁,上述四个内部表示结构直到网页被销毁都一直存在。

最后就是根据绘图上下文来生成最终图像了,这一过程主要依赖2D和3D图形库。

生成过程的简单描述如下图所示:

整个渲染的流程至此便是结束了,从渲染的整个过程中我们也可以发现,原来 CSS、图片、视频等资源的加载是异步的,同 dom 树的构建是并发的,而 Javascript 资源的加载和执行却是同步的,这个过程会阻塞 dom 树的构建,同时当然也会阻碍后续资源(比如图片资源)的下载,因为这时候webkit对需要什么资源一无所知,这导致了资源不能并发下载这一严重的性能问题。(其实对于这样的情况,webkit采取了资源预扫描和预加载的机制来实现资源的并发下载而不被 Javascript 的执行所阻碍,但仍要避免这种情况的出现,因为并不是所有的渲染引擎都做了如此的考虑)。所以从这里我们也可以得到一些关于渲染优化方面的启示:

1 最好把脚本文件放在HTML文件的末尾,这样就不会阻塞 dom 树的构建和资源的并发下载

2 如果非要把脚本文件放在HTML文件的前面,请给 script 标签添加 “async” 属性或者 “defer” 属性。前者表明这是一段可以异步执行的 Javascript 代码,而后者表示在加载完 Javascript 之后延迟到 dom 树构建就绪之后再执行代码。如果同时添加 “async” 和 “defer” ,在同时支持这两个属性的浏览器中 “async” 会覆盖掉 “defer”。需要注意的一点是,如果当前添加 “async” 属性的脚本文件依赖有其他的脚本文件,可能会导致添加 “async” 属性的脚本文件先于依赖脚本执行,即使依赖脚本先于添加 “async” 属性的脚本文件被定义。

webkit 渲染机制的更多相关文章

  1. 2013 QCon北京演讲:跨终端的WebKit渲染机制

    转载请注明原文地址:http://blog.csdn.net/milado_nju 1. 该演讲主要介绍WebKit的渲染机制的内部工作原理和一些新的技术,特别是针对不断出现的多种终端所做的一些努力. ...

  2. 理解WebKit和Chromium: Chromium WebView和Chrome浏览器渲染机制

    转载请注明原文地址:http://blog.csdn.net/milado_nju ## 数据对比 前面介绍过Chromium WebView的时候,说过有关ChromiumWebView同Chrom ...

  3. JS学习笔记:(一)浏览器页面渲染机制

    浏览器的内核主要分为渲染引擎和JS引擎.目前市面上常见的浏览器内核可以分为这四种:Trident(IE).Gecko(火狐).Blink(Chrome.Opera).Webkit(Safari).这里 ...

  4. WebKit 渲染过程

    webkit笔记,主要来自 朱永盛 <WebKit技术内幕> 学习笔记,转载就注明原著,该书是国内仅有的Webkit内核的书籍,学习的好导师,推荐有兴趣的朋友可以购买 Webkit渲染过程 ...

  5. [转]浏览器渲染机制——一定要放在body底部的js引用

    转自:http://blog.csdn.net/u012251421/article/details/50536265 说明: 本文提到的浏览器均是指Chrome. “script标签“指的都是普通的 ...

  6. Android渲染机制和丢帧分析

    http://blog.csdn.net/bd_zengxinxin/article/details/52525781 自己编写App的时候,有时会感觉界面卡顿,尤其是自定义View的时候,大多数是因 ...

  7. Vue项目预渲染机制引入实践

    周末想顺便把已经做好静态页面的webApp项目做一下SEO优化,由于不想写蹩脚的SSR代码,所以准备采用预渲染,本来想着网上有这么多预渲染的文章,随便找个来跟着做不就完了嘛,结果年轻的我付出了整个周末 ...

  8. float浮动-清浮动BFC渲染机制

    float浮动,用于横向布局. 起初的横向布局都用display:inline-block,但是这会导致两个元素之间有空隙,而这是由代码换行解析成空格的,解决元素间有空隙,空格:font-size:0 ...

  9. 转---JS 一定要放在 Body 的最底部么?聊聊浏览器的渲染机制

    作者:德来 segmentfault.com/a/1190000004292479 如有好文章投稿,请点击 → 这里了解详情 一.从一个面试题说起 面试前端的时候我喜欢问一些看上去是常识的问题.比如: ...

随机推荐

  1. phpMyAdmin安装与配置(涉及LAMP配置)

    作者:zccst 安装一个phpMyAdmin还真麻烦,遇到很多问题.不过在解决过程中发现,PHP的水还真深,不是短时间可以看透的. 1,下载 建议去百度软件中心下载 2,使用 (1)解压后,复制配置 ...

  2. 位图文件(BMP)格式以及Linux下C程序实现(转)

    源:位图文件(BMP)格式以及Linux下C程序实现 说到图片,位图(Bitmap)当然是最简单的,它是Windows显示图片的基本格式,其文件扩展名为*.BMP.由于没有经过任何的压缩,故BMP图 ...

  3. 创建和使用MySQL计划事件

    查看事件调度程序线程的状态: SHOW PROCESSLIST; 要启用和启动事件调度程序线程命令: SET GLOBAL event_scheduler = ON; 禁用和停止事件调度程序线程: S ...

  4. vuejs 子组件传递父组件的第二种方式

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. Java的进制转换操作(十进制、十六进制、二进制)

    2014-05-06 17:34 吴文付 最近由于工作上的需要,遇到进制转换的问题.涉及到的进制主要是 十进制,十六进制,二进制中间的转换. 这里整理一下.具体的计划为:封装一个转换类,一个测试类. ...

  6. pandas 按照列A分组,将同一组的列B求和,生成新的Dataframe

    对于pandas中的Dataframe,如果需要按照列A进行分组,将同一组的列B求和,可以通过下述操作完成: df = df.groupby(by=['column_A'])['column_B']. ...

  7. Java数据流的一般操作规律总结

    流的操作规律: 1,明确源和目的. 数据源:就是需要读取,可以使用两个体系:InputStream.Reader: 数据汇:就是需要写入,可以使用两个体系:OutputStream.Writer: 2 ...

  8. Java语言Socket接口用法详解

    Socket接口用法详解   在Java中,基于TCP协议实现网络通信的类有两个,在客户端的Socket类和在服务器端的ServerSocket类,ServerSocket类的功能是建立一个Serve ...

  9. m3u8的浏览器播放器

    前几天花了点时间研究了下怎么在浏览器中播放m3u8的视频地址,最后终于找到了两个开源的东西可以正常播放,稍稍整理下方便后来人. m3u8是什么就不介绍了,现在所有视频网站基本都是通过m3u8的方式来播 ...

  10. Mac下启动MySQL出现错误“the /usr/local/mysql/data directory is not owned by the 'mysql' or '_mysql' user”解决

    错误如下: Warring the /usr/local/mysql/data directory is not owned by the 'mysql' or '_mysql' user 这应该是某 ...