JavaScript事件在WebKit中的处理流程研究

本文主要探讨了JavaScript事件在WebKit中的注册和触发机制。

JS事件有两种注册方式: 通过DOM节点的属性添加或者通过node.addEventListener()函数注册;

通过DOM节点的属性添加如下所示,节点的属性采用on后面紧接event name的形式,比如onclick, onload;

<html>
<head>
<script type="text/javascript">
  function listener(e){
    alert("hello world!");
  }
</script>
</head>
<body>
<button onclick="listener(event)">click</button>
</body>
</html>

通过addEventListener()函数注册的形式如下, 其完整的形式是:target.addEventListener(type, listener[, useCapture]);其中type为事件类型,listener为响应函数,
useCapture表示是否在capture阶段触发,如果不指定,则为false; 

<div>
<button id="button">button</button>
<script type="text/javascript">
  document.getElementById('button').addEventListener("click", listener);
</script>
</div>

WebKit中事件相关的类关系如上图所示:

1. EventTargetDatatMap: 全局映射表,建立了Node与EventTargetData之间的映射关系 ;

2. EventTargetData:   成员变量firingEventIterators是Vector, 用于记录正在触发的事件类型,当该Vector非空时,也表示当前正处于firing阶段; 成员变量eventListenerMap是EventlListenerMap类型;

3. EventlListenerMap:按事件类型分类保存了EventListeners;  成员变量m_entires是Vector,其中每一项可以简化为std::pair<EventType, EventListenerVector>类型;

4. JSLazyEventListener: 最终响应事件触发的对象; 保存了JS执行的基本信息(源码或者JSObject类型的函数对象);

第一种情况下,开始事件注册的时机是发生在页面解析阶段,当创建对了button元素以后,解析到onclick属性,会根据属性值创建对应的EventListener; 这种情况下的EventListener仅保存了JS源码(还没有转换成JSC虚拟机内部的函数对象), 并将EventListener添加到全局Hash表中;

第二种情况下,JS在虚拟机中执行到”addEventListener()"时,会根据JSBindings建立的映射关系,最终调用到WebCore中的native实现Node::addEventListener(), 该函数会根据虚拟机中传递过来的函数对象创建EventListener,并在全局Hash表中建立起target node与EventListener(即这里的button)的映射关系;

下图是两种情况下,事件注册的流程对比:

事件触发流程有以下几个步骤:

1. 找到响应事件的target node: 如果是用户交互事件,通过Hit Test算法确定;  如果是浏览器内部生成的事件,一般有固定的响应节点,比如load事件的target node是body节点;

2. 事件分发:事件在document与target之间按照(capture, at_target, bubble)的顺序进行分发,capture按照从根节点document到子节点target的路径,而bubble则相反;

3. 事件响应:分发流程中,如果事件分发到的当前节点注册了该类型的事件,并且useCapure与事件的分发的顺序一致(即capture阶段时,当前节点注册了useCapture == true的事件), 则进行事件响应; 事件响应分成两步: (1) 从全局映射表中找到当前node对应的EventListeners;(2)将EventListeners封装的JS(源码或者JSC的函数对象)抛到JS虚拟机中执行(下图是mouseup事件的触发时序):

如前所述,属性中注册的事件在EventListener中仅保存了源码,所以开始执行之前会对源码进行必要的转换,格式化成如下形式:

      "(function(event) {listener(event)\n})"

简单来讲,事件注册是建立node与响应函数的映射关系的过程 ,这种映射关系基于事件类型进行分类; 而事件触发则是基于这种映射关系,在不同阶段(capture, bubble)响应注册函数的过程;

(转载请注明出处:http://write.blog.csdn.net/postedit/40620721)

时间: 2024-08-29 18:36:55

JavaScript事件在WebKit中的处理流程研究的相关文章

javascript事件监听中传递匿名函数(嵌套定义的命名函数)与命名函数的区别

项目中有个需求,事件第一次执行(立即执行)与后几次执行不同,但是直接传递定义好的命名函数,返回结果一样..如果通过匿名函数内再嵌套具名函数,结果就能返回正确!代码如下: 代码 <button class="button">按钮</button> (function(w) { //第一次定义需要执行的代码块 var fn = function() { console.log(1); }; var btn = document.querySelector('.but

webkit中DOM 事件有多少

webkit中DOM 事件有多少 目前客户端javascript中大量的工作就是处理浏览器,用户触发的各种事件,下面是webkit中这些事件的集合,有一些时常见的,标准规定的,而另一些则是webkit自己扩展,自定义的,比如beforeloadEvent,这个事件可以说是专门为广告过滤做准备的,像copy,cut,paste事件,可以直观看出其用意,但是这些却都非w3c所规定的标准事件,也不一定为其他浏览器支持(至少ie不支持),但是却非常有用 后续会不断介绍,这些事件, abort befor

Javascript事件冒泡,没有想象中那么糟糕

Javascript事件冒泡,没有想象中那么糟糕  提到js事件,我们可能第一时间反应的就是“如何阻止事件冒泡”:但是事件冒泡真的是如我们想象的那么糟糕吗? 1. Event 对象  Event 对象代表事件的状态,比如事件在其中发生的元素.键盘按键的状态.鼠标的位置.鼠标按钮的状态. 2. 事件句柄 (Event Handlers)  指能够使 HTML 事件触发浏览器中的行为,比如点击(onclick).鼠标悬浮(onfocus)等 3. 什么是事件冒泡  一个对象(event.srcEle

JavaScript事件委托原理及Jquery中的事件委托

概念 事件委托,通俗来说就是将元素的事件委托给它的父级或者更外级元素处理. 事件流 事件流描述的是从页面中接收事件的顺序. 事件冒泡:事件开始由最具体的元素接收,然后逐级向上传播到较为不具体的节点(或文档). 事件捕获:事件开始由不太具体的节点接收,然后逐级向下传播到最具体的节点.它与事件冒泡是个相反的过程. DOM2级事件规定的事件流包括三个阶段: 事件捕获 目标阶段 事件冒泡 原理 事件委托就是利用事件冒泡机制实现的. 假设有一个列表,要求点击列表项弹出对应字段. <ul id="my

记一次途家面试中问到的JavaScript事件机制:Event Loop

前几天去途家面试,问到了事件机制,以及异步队列的问题.很遗憾,当时答错了.回来之后查了下资料,看到阮一峰老师博客的分析,感觉讲的非常浅显易懂,就分享过来了. 一.为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. JavaScript的单线程,与它的用途有关.作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM.这决定了它只能是单线程,

浏览器中的JavaScript事件循环机制

浏览器的事件循环机制是HTML中定义的规范. JavaScript有一个主线程和调用栈,所有的任务都会被放到调用栈等待主线程执行. JS调用栈 是一种先进后出的数据结构.当函数被调用时,会被添加到栈中的顶部,执行完成之后就从栈的顶部移除该函数,直到栈内被清空. 同步任务.异步任务 JS单线程任务分为同步任务和异步任务.同步任务会在调用栈中按照顺序排队等待主线程执行,异步任务则会在异步有了结果之后将注册的回调函数添加到任务队列(消息队列)中等待主线程空闲的时候,也就是栈内被清空的时候,被读取到栈中

Chromium分发输入事件给WebKit处理的过程分析

Chromium的Render进程接收到Browser进程分发过来的输入事件之后,会在Compoistor线程中处理掉滑动和捏合手势这两种特殊的输入事件,其它类型的输入事件则交给Main线程处理.Main线程又会进一步将输入事件分发给WebKit处理.WebKit则根据输入事件发生的位置在网页中找到对应的HTML元素进行处理.本文接下来详细分析Chromium分发输入事件给WebKit处理的过程. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! 以Touc

JavaScript事件代理入门

事件代理(Event Delegation),又称之为事件委托.是 JavaScript 中常用绑定事件的常用技巧. 顾名思义,"事件代理"即是把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务. 为什么要这样做呢? 众所周知,DOM操作是十分消耗性能的.所以重复的事件绑定简直是性能杀手.而事件代理的核心思想,就是通过尽量少的绑定,去监听尽量多的事件. 下面将会用 Zepto 为大家演示怎么实现事件代理. 啊?Zepto是什么? Zepto is a minimalist J

JavaScript异步编程(一) 深入理解JavaScript事件

JavaScript异步编程 深入理解JavaScript事件 ?事件的调度 JavaScript事件处理器在线程空闲之前不会运行 线程的阻塞 var start = new Date(); // setTimeout和setInterval的计时精度比期望值差 setTimeout(function(){ var end = new Date(); console.log('Time elapsed', end - start, 'ms'); }, 500); while(new Date -