浏览器工作大流程

从上面这个图中,我们可以看到那么几个事:

1)浏览器会解析三个东西:

  • 一个是HTML/SVG/XHTML,事实上,Webkit有三个C++的类对应这三类文档。解析这三种文件会产生一个DOM Tree。
  • CSS,解析CSS会产生CSS规则树。
  • Javascript,脚本,主要是通过DOM API和CSSOM API来操作DOM Tree和CSS Rule Tree.

2)解析完成后,浏览器引擎会通过DOM Tree 和 CSS Rule Tree 来构造 Rendering Tree。注意:

  • Rendering Tree 渲染树并不等同于DOM树,因为一些像Header或display:none的东西就没必要放在渲染树中了。
  • CSS 的 Rule Tree主要是为了完成匹配并把CSS Rule附加上Rendering Tree上的每个Element。也就是DOM结点。也就是所谓的Frame。
  • 然后,计算每个Frame(也就是每个Element)的位置,这又叫layout和reflow过程。

3)最后通过调用操作系统Native GUI的API绘制。

DOM

HTML的DOM Tree解析如下:

<html>
<html>
<head>
    <title>Web page parsing</title>
</head>
<body>
    <div>
        <h1>Web page parsing</h1>
        <p>This is an example Web page.</p>
    </div>
</body>
</html>

上面这段HTML会解析成这样:

下面是另一个有SVG标签的情况。

CSS的解析大概是下面这个样子(下面主要说的是Gecko也就是Firefox的玩法),假设我们有下面的HTML文档:

<doc>
<title>A few quotes</title>
<para>
  Franklin said that <quote>"A penny saved is a penny earned."</quote>
</para>
<para>
  FDR said <quote>"We have nothing to fear but <span>fear itself.</span>"</quote>
</para>
</doc>

于是DOM Tree是这个样子:

于是DOM Tree是这个样子:

然后我们的CSS文档是这样的:

/* rule 1 */ doc { display: block; text-indent: 1em; }
/* rule 2 */ title { display: block; font-size: 3em; }
/* rule 3 */ para { display: block; }
/* rule 4 */ [class="emph"] { font-style: italic; }

于是我们的CSS Rule Tree会是这个样子:

注意,图中的第4条规则出现了两次,一次是独立的,一次是在规则3的子结点。所以,我们可以知道,建立CSS Rule Tree是需要比照着DOM Tree来的。CSS匹配DOM Tree主要是从右到左解析CSS的Selector,好多人以为这个事会比较快,其实并不一定。关键还看我们的CSS的Selector怎么写了。

注意:CSS匹配HTML元素是一个相当复杂和有性能问题的事情。所以,你就会在N多地方看到很多人都告诉你,DOM树要小,CSS尽量用idclass,千万不要过渡层叠下去,……

通过这两个树,我们可以得到一个叫Style Context Tree,也就是下面这样(把CSS Rule结点Attach到DOM Tree上):

所以,Firefox基本上来说是通过CSS 解析生成 CSS Rule Tree,然后,通过比对DOM生成Style Context Tree,然后Firefox通过把Style Context Tree和其Render Tree(Frame Tree)关联上,就完成了。注意:Render Tree会把一些不可见的结点去除掉。而Firefox中所谓的Frame就是一个DOM结点,不要被其名字所迷惑了

注:Webkit不像Firefox要用两个树来干这个,Webkit也有Style对象,它直接把这个Style对象存在了相应的DOM结点上了。

渲染的流程基本上如下(黄色的四个步骤):

  • 计算CSS样式
  • 构建Render Tree
  • Layout - 定位坐标和大小,是否换行,各种position, overflow, z-index属性 ……
  • 正式开画

注意:上图流程中有很多连接线,这表示了Javascript动态修改了DOM属性或是CSS属会导致重新Layout,有些改变不会,就是那些指到天上的箭头,比如,修改后的CSS rule没有被匹配到,等。

这里重要要说两个概念,一个是Reflow,另一个是Repaint。这两个不是一回事。

  • Repaint——屏幕的一部分要重画,比如某个CSS的背景色变了。但是元素的几何尺寸没有变。
  • Reflow——意味着元件的几何尺寸变了,我们需要重新验证并计算Render Tree。是Render Tree的一部分或全部发生了变化。这就是Reflow,或是Layout。(HTML使用的是flow based layout,也就是流式布局,所以,如果某元件的几何尺寸发生了变化,需要重新布局,也就叫reflow)reflow 会从<html>这个root frame开始递归往下,依次计算所有的结点几何尺寸和位置,在reflow过程中,可能会增加一些frame,比如一个文本字符串必需被包装起来。

下面是一个打开Wikipedia时的Layout/reflow的视频(注:HTML在初始化的时候也会做一次reflow,叫 intial reflow),你可以感受一下:

Reflow的成本比Repaint的成本高得多的多。DOM Tree里的每个结点都会有reflow方法,一个结点的reflow很有可能导致子结点,甚至父点以及同级结点的reflow。在一些高性能的电脑上也许还没什么,但是如果reflow发生在手机上,那么这个过程是非常痛苦和耗电的

所以,下面这些动作有很大可能会是成本比较高的。

  • 当你增加、删除、修改DOM结点时,会导致Reflow或Repaint
  • 当你移动DOM的位置,或是搞个动画的时候。
  • 当你修改CSS样式的时候。
  • 当你Resize窗口的时候(移动端没有这个问题),或是滚动的时候。
  • 当你修改网页的默认字体时。

注:display:none会触发reflow,而visibility:hidden只会触发repaint,因为没有发现位置变化。

多说两句关于滚屏的事,通常来说,如果在滚屏的时候,我们的页面上的所有的像素都会跟着滚动,那么性能上没什么问题,因为我们的显卡对于这种把全屏像素往上往下移的算法是很快。但是如果你有一个fixed的背景图,或是有些Element不跟着滚动,有些Elment是动画,那么这个滚动的动作对于浏览器来说会是相当相当痛苦的一个过程。你可以看到很多这样的网页在滚动的时候性能有多差。因为滚屏也有可能会造成reflow。

基本上来说,reflow有如下的几个原因:

  • Initial。网页初始化的时候。
  • Incremental。一些Javascript在操作DOM Tree时。
  • Resize。其些元件的尺寸变了。
  • StyleChange。如果CSS的属性发生变化了。
  • Dirty。几个Incremental的reflow发生在同一个frame的子树上。

好了,我们来看一个示例吧:

var bstyle = document.body.style; // cache

bstyle.padding = "20px"; // reflow, repaint
bstyle.border = "10px solid red"; //  再一次的 reflow 和 repaint

bstyle.color = "blue"; // repaint
bstyle.backgroundColor = "#fad"; // repaint

bstyle.fontSize = "2em"; // reflow, repaint

// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode(‘dude!‘));

当然,我们的浏览器是聪明的,它不会像上面那样,你每改一次样式,它就reflow或repaint一次。一般来说,浏览器会把这样的操作积攒一批,然后做一次reflow,这又叫异步reflow或增量异步reflow。但是有些情况浏览器是不会这么做的,比如:resize窗口,改变了页面默认的字体,等。对于这些操作,浏览器会马上进行reflow。

但是有些时候,我们的脚本会阻止浏览器这么干,比如:如果我们请求下面的一些DOM值:

  • offsetTop, offsetLeft, offsetWidth, offsetHeight
  • scrollTop/Left/Width/Height
  • clientTop/Left/Width/Height
  • IE中的 getComputedStyle(), 或 currentStyle

因为,如果我们的程序需要这些值,那么浏览器需要返回最新的值,而这样一样会flush出去一些样式的改变,从而造成频繁的reflow/repaint。

减少reflow/repaint

下面是一些Best Practices:

1)不要一条一条地修改DOM的样式。与其这样,还不如预先定义好cssclass,然后修改DOMclassName

// bad
var left = 10,
top = 10;
el.style.left = left + "px";
el.style.top  = top  + "px";

// Good
el.className += " theclassname";

// Good
el.style.cssText += "; left: " + left + "px; top: " + top +"px;";

2)DOM离线后修改。如

  • 使用documentFragment 对象在内存里操作DOM
  • 先把DOM给display:none(有一次repaint),然后你想怎么改就怎么改。比如修改100次,然后再把他显示出来。
  • clone一个DOM结点到内存里,然后想怎么改就怎么改,改完后,和在线的那个的交换一下。

3)不要把DOM结点的属性值放在一个循环里当成循环里的变量。不然这会导致大量地读写这个结点的属性。

4)尽可能的修改层级比较低的DOM。当然,改变层级比较底的DOM有可能会造成大面积的reflow,但是也可能影响范围很小。

5)为动画的HTML元件使用fixedabsoultposition,那么修改他们的CSS是不会reflow的。

6)千万不要使用table布局。因为可能很小的一个小改动会造成整个table的重新布局。

In this manner, the user agent can begin to lay out the table once the entire first row has been received. Cells in subsequent rows do not affect column widths. Any cell that has content that overflows uses the ‘overflow’ property to determine whether to clip the overflow content.

Fixed layout, CSS 2.1 Specification

This algorithm may be inefficient since it requires the user agent to have access to all the content in the table before determining the final layout and may demand more than one pass.

Automatic layout, CSS 2.1 Specification

几个工具和几篇文

有时候,你会也许会发现在IE下,你不知道你修改了什么东西,结果CPU一下子就上去了到100%,然后过了好几秒钟repaint/reflow才完成,这种事情以IE的年代时经常发生。所以,我们需要一些工具帮我们看看我们的代码里有没有什么不合适的东西。

  • Chrome下,Google的SpeedTracer是个非常强悍的工作让你看看你的浏览渲染的成本有多大。其实Safari和Chrome都可以使用开发者工具里的一个Timeline的东东。
  • Firefox下这个基于Firebug的叫Firebug Paint Events的插件也不错。
  • IE下你可以用一个叫dynaTrace的IE扩展。

最后,别忘了下面这几篇提高浏览器性能的文章:

时间: 2024-10-08 22:16:37

浏览器工作大流程的相关文章

浏览器工作原理——页面加载

浏览器工作大流程 来看个图: 从上面这个图中,我们可以看到那么几个事: 1)浏览器会解析三个东西: 一个是HTML/SVG/XHTML,事实上,Webkit有三个C++的类对应这三类文档.解析这三种文件会产生一个DOM Tree. CSS,解析CSS会产生CSS规则树. Javascript,脚本,主要是通过DOM API和CSSOM API来操作DOM Tree和CSS Rule Tree. 2)解析完成后,浏览器引擎会通过DOM Tree 和 CSS Rule Tree 来构造 Render

浏览器工作原理及相关内核、技术介绍

好吧,我最喜欢的就是原理方面的介绍了..好处有两个:1.了解原因更方便与工(zhuang)作(bi):2.原理都是相同的,大道归一啊(吐) 正文开始: 一.浏览器工作原理(简化版) 1.浏览器用来干什么用 浏览器的主要功能是将用户请求访问的web资源呈现出来,它需要从服务器请求资源,并将其显示在浏览器窗口中,资源的格式通常是HTML,也包括PDF.image及其他格式.用户用URI(Uniform Resource Identifier 统一资源标识符)来指定所请求资源的位置. HTML和CSS

[转帖]浏览器工作原理

浏览器工作原理详解 原贴地址不详 .. 这篇文章是以色列开发人员塔利·加希尔的研究成果.她在查阅了所有公开发布的关于浏览器内部机制的数据,并花了很多时间来研读网络浏览器的源代码.她写道: 在 IE 占据 90%市场份额的年代,我们除了把浏览器当成一个“黑箱”,什么也做不了.但是现在,开放源代码的浏览器拥有了过半的市场份额,因此,是时候来揭开神秘的面纱,一探网络浏览器的内幕了.呃,里面只有数以百万行计的C++ 代码… 本篇文章的英文原版:How Browsers Work: Behind the

浏览器工作原理

浏览器工作原理的实质就是实现http协议的通讯,具体过程如下: HTTP通信的流程,大体分为三个阶段:1. 连接 服务器通过一个ServerSocket类对象对8000端口进行监听,监听到之后建立连接,打开一个socket虚拟文件.2. 请求 创建与建立socket连接相关的流对象后,浏览器获取请求,为GET请求,则从请求信息中获取所访问的HTML文件名,向服务器发送请求.3. 应答 服务收到请求后,搜索相关目录文件,若不存在,返回错误信息.若存在,则想html文件,进行加HTTP头等处理后响应

应届生校招找工作完整流程总结

原文发表自我的个人主页,请看原文,多谢支持 http://purplesword.info/get-job 昨天有同学问我找工作方面的事,感觉有很多疑问,想想有必要把我找工作那段时间学到的东西简单做个总结,供有需要的同学参考. 在找工作之前,和很多同学一样我有很多疑问,比如什么时候找工作这种事都不了解,但是找到工作之后,又忘了当初有哪些疑问.为了让这篇写的完整一点,我特地让一位对找工作不太了解.不愿透漏姓名的.机智的学弟帮忙,把他的疑问全部说出来,然后我汇总进行一个完整的总结.尤其是很多"脑残&

业务流的另外一种场景:工作协同流程

今天给开发的讨论业务流程,其中一个业务部门土匪甲的说道,我的流程可能不是固定的,随时可变怎么办? 这下子开发的蒙圈了,屌丝A叫道:那怎么行,你老变来变去,怎么画流程? 另一个屌丝B说,你老变,是不守规矩,说明你还没有搞清楚自己要做什么.你先搞明白了我们在讨论如何定义流程吧. 我在旁边看他们撕逼,自己在想土匪甲要求的合理性,在现实中有没有应用场景. 一般来讲,企业中的业务流程相对是比较稳定的,很多流程系统也是基于这个假设进行开发和设计,并据此划出流程图,绑定上业务逻辑. 但是实际中,除了这些"典型

uWSGI+django+nginx的工作原理流程与部署历程

一.前言献给和我一样懵懂中不断汲取知识,进步的人们. 霓虹闪烁,但人们真正需要的,只是一个可以照亮前路的烛光 二.必要的前提2.1 准备知识 django一个基于python的开源web框架,请确保自己熟悉它的框架目录结构.1uWSGI一个基于自有的uwsgi协议.wsgi协议和http服务协议的web网关1nginx常用高性能代理服务器1wsgi.pydjango项目携带的一个wsgi接口文件如果项目名叫destiny的话,此文件就位于[destiny/destiny/wsgi.py]122.

【转】uWSGI+django+nginx的工作原理流程与部署历程

一.前言献给和我一样懵懂中不断汲取知识,进步的人们. 霓虹闪烁,但人们真正需要的,只是一个可以照亮前路的烛光 二.必要的前提 2.1 准备知识 1.django 一个基于python的开源web框架,请确保自己熟悉它的框架目录结构. 2.uWSGI 一个基于自有的uwsgi协议.wsgi协议和http服务协议的web网关 3.nginx 常用高性能代理服务器 4.wsgi.py django项目携带的一个wsgi接口文件 如果项目名叫destiny的话,此文件就位于[destiny/destin

了解浏览器工作原理-初步

作者:zccst 同样,先感谢同事们的技术分享,使我开始关注浏览器工作原理.(其实很早就想关注,但由于各种各样的原因一直拖延着) 先留一个链接,慢慢攒着 浏览器的工作原理:新式网络浏览器幕后揭秘(转)了解浏览器工作原理-初步,布布扣,bubuko.com