IT-北北报

Webkit内核-Render树

2017/03 22 17:03

RenderObject类

RenderObject是Render树的节点基础类,提供了一组公共的接口。

webkit0

 

在DOM树中,分为“可视节点”与“非可视节点”,比如”head”、“script”就是典型的“非可视节点”,而“body”、“div”、“canvas”等这些节点通常情况下为“可视节点”,这些节点会呈现一块区域。

对于“可视节点”,Webkit会为他们创建相应的RenderObject对象,一个RenderObject对象保存了为绘制DOM节点所需要的各种信息,如样式布局信息,元素颜色信息。页面上所有的节点构成了RenderObject树,这里要注意,RenderObject树节点和DOM节点不是一一对应关系,下边三个原则会被创建RenderObject节点:

  • DOM树的document节点;
  • DOM树中的“可视节点”;Webkit不会为非可视节点创建RenderObject节点;
  • 某些情况下Webkit匿名RenderObject节点,这些节点不应用于DOM树中的节点,典型的例子是RenderBlock节点。

 

 

匿名RenderBlock对象

 

CSS中有块级元素和内嵌(inline)元素之分。内嵌元素表现的是行布局形式,就是说这些元素以行进行显示。以 div 元素为例,如果设置属性 style 为 display:inline 时,则那是内嵌元素,那么它可能与前面的元素在同一行;如果该元素没有设置这个属性时,则是块级元素,那么在新的行里显示。

 

RenderBlock用来是用来表示块级元素, 为了处理上的方便,某些情况下需要建立匿名的RenderBlock对象,因为RenderBlock的子女必须都是内嵌的元素或者都是非内嵌的元素。所以,当它包含两种元素的时候,那么它会为相邻的内嵌元素创建一个块级RenderBlock节点,然后设置该节点为自己的子女并且设置这些内嵌元素为它的子女。

 

影子DOM

对于影子DOM,就是在DOM节点中还没有实际appendChild的节点,它可能是由createElement方法产生的内容,Javascript代码没有办法访问影子DOM,Webkit需要创建并渲染RenderObject对象,但是不需要把它转换为RenderObject节点。

 

Element类

 

RenderObject对象包含Element类,每个Element对象都会递归调用”attach”函数,该函数检查Element对象是否需要创建RenderObject节点,如果需要会使用NodeRenderingContext类来根据DOM节点的类型来创建RenderObject节点。

 

层次和RenderLayer对象

 

网页是可以分层的,这有俩点原因,一是方便网页开发者开发网页并设置网页层次,二是为了Webkit在处理时更便捷。

在某些类型的RenderObject节点或具有某些CSS样式的RenderObject节点出现时,Webkit就会为这些节点创建RenderLayer对象。RenderLayer创建的基本原则如下:

  • DOM树中Document节点对应的RenderView节点;
  • DOM树中的Document的子女节点,也就是HTML节点对应的RenderBlock节点;
  • 显示的指定CSS位置的RenderObject节点;
  • 有透明效果的RenderObject节点;
  • 节点有溢出(overflow)、alpha或反射等效果的RenderObject节点;
  • 使用Canvas 2D和3D(WebGL)技术的RenderObject节点;
  • Video节点对应的RenderObject节点。

     

 

为了直观感受这三种树,如下给出了这三种树及其它们之间的对应关系:

webkit1

 

由此可见他们三者相互之间并不是一一对应的关系。

 

 

 

欢迎关注公众号,我们会不定期分享前沿技术、学习资料,在前端的道路上一起成长

qrcode_public

Webkit内核-节点渲染与JS执行原理

2017/03 09 09:03
webkit-logo

简介

在Webkit中,节点的渲染是由HTMLContructionSite类来完成的,该类包含一个DOM树的根节点HTMLDocument对象,其它的元素都是它的后代元素。

因为HTML文档的Tag标签是有开始结束标记的,所以构建过程使用栈结构是再合适不过的。HTMLContructionSite类中包含一个HTMLElementStack变量,它是一个保存元素节点的栈,在其中的元素就是当前有开始标记但还没有结束标记的的元素节点。

 

实例

一个HTML片段如:

 

<body><div><img></img></div></body>

解释器先做入栈操作,当解释到img元素的开始标记时,栈中的元素就是body、div和img,当遇到img的结束标记时,img出栈,img是div的子元素,当遇到div的结束标记时,div出栈,表明div和它的子女都已经处理完毕,以此类推。

根据DOM标准中的定义,节点有很多中类型、属性,所以他们有一个基础的父类 — Node类。

在Webkit中,DOM中的接口Interface对应于C++的类,Node类是其它类的基类,Node类实际上继承自EventTarget类,它表明Node类能够接受事件;同时,Node类还继承自另外一个关键的基类 — ScriptWrappable,这个与Javascript引擎密切相关。

webkit-nodeElement

Javascript的执行

在HTML解释器工作中,可能会有Javascript代码需要执行,它发生在将字符串解析成词语后创建节点时。这也是为什么全局执行的Javascript代码不能访问DOM树的原因,因为DOM在那个时间点还没有被创建出来。

Webkit将DOM树创建过程中需要执行的Javascript代码交给HTMLScriptRunner类来负责。原理就是利用Javascript引擎来执行Node节点中包含的代码。

因为JS代码可能会调用”document.write”等方法来修改文档结构,所以JS代码的执行会阻碍后面节点的创建,同时也会阻碍后边资源的下载,这也是JS阻塞加载的原理所在。

所以会有俩点建议:

1.将script标签加上”async”属性,说明这是一个可以异步执行的JS代码;

2.将script元素放在body的最后。(更推荐一些)

然而Webkit在这方面进行了一些优化,当遇到需要执行的JS代码时,Webkit会先暂停执行,使用预先扫描器HTMLPreloadScanner类扫描后面的词语。如果Webkit发现有其它资源需要加载,则使用资源加载器HTMLResourcePreloader类来请求资源,在这之后才执行JS代码。预先扫描并不会真实创建节点,所以速度较快。但是并不是所有渲染引擎都做了相关优化,所以第二种方式会更被推荐一些。

 

DOMContentLoaded

当Dom树创建完成后,Webkit触发了”DOMContentLoaded”事件,这就是我们熟悉的window.onload函数,此时一些代码才会在资源加载完成后执行,避免了DOM还没创建就出现操作的问题。

 

另外您可以关注我的公众号,更多技术文章将通过公众号进行分享

qrcode_public

ReactEasyUI开源组件库上线啦

2017/01 23 16:01

ReactEasyUI是刚刚出品的一套React的开源组件库,希望能给大家提供一些帮助。

接下来我们将在2017年持续维护这个组件库,争取把它做成一个精品组件库,各位大神也可以给我们留言发表意见,也许下一个版本就会有你想要的组件。

闲言碎语不要讲,github和npm的地址与安装方法如下:

github(API地址):https://reacteasyui.github.io

npm安装方法:npm install reacteasyui –save-dev

接下来强力推荐一下我们的ReactEasyUI

 

基础组件部分

640.webp

freecheckbox.webp

textwithcount.webp

switchbtn.webp

 

日期组件部分

datechooser1.webp

datechooser3.webp

datechooser5.webp

calender.webp

AppCalender

用于移动端的日历组件

appcalender.webp

 

部分进度条相关组件

piechart.webp

Progressbar.webp

ProgressChart.webp

部分图表组件

pieandline.webp

pie.webp

line.webp

multiple.webp

欢迎关注公众号,我们会不定期分享前沿技术、学习资料,在前端的道路上一起成长

qcode.webp


无觅相关文章插件,快速提升流量

友荐云推荐