主题:【原创】新时代新潮流WebOS 【1】 -- 邓侃
【22】WebKit,鼠标引发的故事,续
Figure 3. The listener binding of Webkit
Courtesy http://farm4.static.flickr.com/3659/3640149732_e55446f6b3_b.jpg
Figure 3 详细描绘了Webkit 设置JavaScript Engine 的全过程。在Webkit 解析HTML文件,生成DOM Tree 和Render Tree 的过程中,当解析到 <img onclick="..." src="..."> 这一句的时候,生成DOM Tree中的 HTMLElement 节点,以及Render Tree 中 RenderImage 节点。如前文所述。在生成HTMLElement 节点的过程中,因为注意到有onclick属性,Webkit决定需要给 HTMLElement 节点绑定一个 EventListener,参见Figure 3 中第7步。
Webkit 把所有EventListener 的创建工作,交给Document 统一处理,类似于 Design Patterns中,Singleton 的用法。也就是说,DOM Tree的根节点 Document,掌握着这个网页涉及的所有EventListeners。 有趣的是,当Document 接获请求后,不管针对的是哪一类事件,一律让代理器 (kjsProxy) 生成一个JSLazyEventListener。之所以说这个实现方式有趣,是因为有几个问题需要特别留意,
1. 一个HTMLElement节点,如果有多个类似于onclick的事件属性,那么就需要多个相应的EventListener object instances与之绑定。
2. 每个节点的每个事件属性,都对应一个独立的EventListener object instance。不同节点不共享同一个 EventListener object instance。即便同一个节点中,不同的事件属性,对应的也是不同的EventListener object instances。
这是一个值得批评的地方。不同节点不同事件对应彼此独立的EventListener object instances,这种做法给不同节点之间的信息传递,造成了很大障碍。反过来设想一下,如果能够有一种机制,让同一个object instance,穿梭于多个HTMLElement Nodes之间,那么浏览器的表现能力将会大大增强,届时,将会出现大量的前所未有的匪夷所思的应用。
3. DOM Tree的根节点,Document,统一规定了用什么工具,去解析事件属性的值,以及执行这个属性值所定义的事件处理逻辑。如前文所述,事件属性的值,分成HTML DOM methods 和JavaScript 两类。但是不管某个HTMLElement节点的某个事件属性的值属于哪一类,Document 一律让 kjsProxy代理器,生成一个 EventListener。
看看这个代理器的名字就知道,kjsProxy生成的 EventListener,一定是依托JavaScriptCore Engine,也就是以前的KJS JavaScript Engine,来执行事件处理逻辑的。核实一下源代码,这个猜想果然正确。
4. 如果想把JavaScriptCore 替换成其它JavaScript Engine,例如Google 的V8,不能简单地更改configuration file,而需要修改一部分源代码。所幸的是,Webkit的架构设计相当清晰,所以需要改动部分不多,关键部位是把 Document.{h,cpp} 以及其它少数源代码中,涉及kjsProxy 的部分,改成其它Proxy即可。
5. kjsProxy 生成的EventListener,是JSLazyEventListener。解释一下JSLazyEventListener 命名的寓意,JS容易理解,意思是把事件处理逻辑,交给JavaScript engine 负责。所谓 lazy 指的是,除非用户在照片显示区域点击了鼠标,否则,JavaScript Engine 不主动处理事件属性的值所规定的事件处理逻辑。
与 lazy做法相对应的是JIT即时编译,譬如有一些JavaScript Engine,在用户尚没有触发任何事件以前,预先编译了所有与该网页相关的JavaScript,这样,当用户触发了一个特定事件,需要调用某些 JavaScript functions时,运行速度就会加快。当然,预先编译会有代价,可能会有一些JavaScript functions,虽然编译过了,但是从来没有被真正执行过。
Figure 4. The event handling of Webkit
Courtesy http://farm4.static.flickr.com/3390/3640149730_0c98f0218d_b.jpg
当解析完HTML文件,生成了完整的DOM Tree 和Render Tree 以后,Webkit就准备好去响应和处理用户触发的事件了。响应和处理事件的整个流程,如Figure 4所描述。整个流程分成两个阶段,
1. 寻找 EventTargetNode。
当用户触发某个事件,例如点击鼠标,根据鼠标所在位置,从Render Tree的根节点开始,一路搜索到鼠标所在位置对应的叶子节点。Render Tree根节点对应的是整个浏览器页面,而叶子节点对应的区域面积最小。
从Render Tree根节点,到叶子节点,沿途每个Render Tree Node,都对应一个DOM Tree Node。这一串DOM Tree Nodes中,有些节点响应用户触发的事件,另一些不响应。例如在本文的例子中,<body> tag 对应的DOM Tree Node,和第一张照片的<img> tag 对应的DOM Tree Node,都对onclick事件有响应。
第一阶段结束时,Webkit得到一个EventTargetNode,这个节点是一个DOM Tree Node,而且是对事件有响应的DOM Tree Node。如果存在多个DOM Tree Nodes对事件有响应,EventTargetNode是那个最靠近叶子的中间节点。
2. 执行事件处理逻辑。
如果对于同一个事件,有多个响应节点,那么JavaScript Engine 依次处理这一串节点中,每一个节点定义的事件处理逻辑。事件处理逻辑,以字符串的形式定义在事件属性的值中。在本文的例子中,HTML文件包含<img onclick="myfunction('World')">,和<body onclick="myfunction('Hello')">,这意味着,有两个DOM Tree Nodes 对onclick事件有响应,它们的事件处理逻辑分别是myfunction('World') 和myfunction('Hello'),这两个字符串。
当JavaScript Engine 获得事件处理逻辑的字符串后,它把这个字符串,根据JavaScript的语法规则,解析为一棵树状结构,称作Parse Tree。有了这棵Parse Tree,JavaScript Engine就可以理解这个字符串中,哪些是函数名,哪些是变量,哪些是变量值。理解清楚以后,JavaScript Engine 就可以执行事件处理逻辑了。本文例子的事件处理过程,如Figure 4中第16步,到第35步所示。
本文的例子中,“myfunction('World')" 这个字符串本身并没有定义事件处理逻辑,而只是提供了一个JavaScript函数的函数名,以及函数的参数的值。当JavaScript Engine 得到这个字符串以后,解析,执行。执行的结果是得到函数实体的代码。函数实体的代码中,最重要的是alert(v) 这一句。JavaScript Engine 把这一句解析成Parse Tree,然后执行。
注意到本文例子中,对于同一个事件onclick,有两个不同的DOM Tree Nodes 有响应。处理这两个节点的先后顺序要么由capture path,要么由bubbling path决定,如Figure 5所示。(Figure 5中对应的HTML文件,不是本文所引的例子)。在HTML文件中,可以规定event.bubbles属性。如果没有规定,那就按照bubbling的顺序进行,所以本文的例子,是先执行<img>,弹出“World” 的窗口,关掉“World”窗口后,接着执行<body>,弹出“Hello” 的窗口。
Figure 5. The capture and bubbling of event by the DOM tree.
Courtesy http://www.w3.org/TR/DOM-Level-3-Events/images/eventflow.png
这一节比较枯燥,因为涉及了太多的源代码细节。之所以这么不厌其烦地说明细节,是为了解决如何更有效率地处理事件,以及提供更丰富的手段去处理事件。待续。
- 相关回复 上下关系8
🙂可惜俺没买 1 邓侃 字42 2009-06-29 07:27:29
🙂邓兄对IT行业的独特眼光,不赚钱也难啊 2 kraft 字116 2009-06-29 08:15:47
🙂邓大莫后悔,Kraft 1 谷品三斋 字76 2009-06-29 07:32:02
🙂【原创】【22】WebKit,鼠标引发的故事,下
🙂现在美国招WEBKIT的程序员的POST有不少。 1 素里太守 字69 2009-06-29 02:37:23
🙂想跳槽? 1 邓侃 字29 2009-06-29 03:10:31
🙂招聘启事是经济的一个重要晴雨表,也是 1 素里太守 字112 2009-06-29 03:19:12
🙂挺好的分析,webkit源码质量相当高,极有教益多谢多谢 1 雨后的假牙 字0 2009-06-23 00:31:47