• 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(typelistener[, 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)
    })"
    

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


    (转载请注明出处:http://blog.csdn.net/codigger/article/details/40620721)


        

         

       


  • 相关阅读:
    构建之法阅读笔记02
    四则运算出题2
    初学delphi
    学习进度第一周
    构建之法阅读笔记01
    四则运算出题1
    个人介绍
    每日工作总结08
    构建之法阅读笔记03
    每日工作总结07
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/6816821.html
Copyright © 2020-2023  润新知