事件循环、事件监听、事件委托

一、事件循环

JavaScript引擎是干什么用的?其实很简单--它的任务就是遍历应用中的每一行JavaScript代码,并且一次执行一行,意味着JavaScript是单线程的。这里最大的影响是:如果在JavaScript代码中有地方会占用大量的时间,那后面的代码都会被block住。
那么JavaScript引擎怎么知道如何一次处理一行JavaScript代码?它使用的是一个调用栈call stack。你可以把调用栈比作电梯--第一个进电梯的会最后一个出电梯,最后进电梯的会最先出。

/* Within main.js */

var firstFunction = function () { console.log("I'm first!"); }; var secondFunction = function () { setTimeout(firstFunction, 5000); console.log("I'm second!"); }; secondFunction(); /* Results: * => I'm second! * (And 5 seconds later) * => I'm first! */

下边模拟调用栈

1、...

2、secondFunction调用setTimeout,setTimeout入栈:

3、setTimeout执行后,浏览器会把setTimeout的回调函数(在这个栗子中是firstFunction)放到Event Table中。Event Table 就是个注册站:调用栈让Event Table注册一个函数,该函数会在5秒之后被调用。当指定的事情发生时,Event Table会将这个函数移到Event Queue。Event Queue其实就是个缓冲区域,这里的函数等着被调用并移到调用栈。
问题来了,什么时候函数会从Event Queue移到调用栈咧?JavaScript引擎依据一条规则:有一个monitoring process(不知翻译成啥好)会持续不断地检查调用栈是否为空,一旦为空,它会检查Event Queue里边是否有等待被调用的函数。如果存在,它就会调用这个Queue中第一个函数并将其移到调用栈中。如果Event Queue为空,那么这个monitoring process会继续不定期的检查。这一整个过程就是Event Loop

4、一旦回调函数加入到Event表中,代码不会被block住,浏览器不会等待5秒之后再继续处理接下去的代码,相反,浏览器继续执行secondFunction的下一行代码,console.log。

5、在background,Event Table会持续地监测是否有事件触发,将函数移到Event Queue中。在这个栗子中,secondFunction执行完毕,接着main.js也执行完毕。

6、从回调函数被放入Event Table后5秒钟,Event Table把firstFucntion移到Event Queue中。

7、由于事件循环持续地监测调用栈是否已空,此时它一注意到调用栈空了,就调用firstFunction并创建一个新的调用栈。

8、一旦firstFunction执行完毕,调用栈空了,Event Table里也没有注册函数,Event Queue也为空。

二、事件监听

事件机制:捕获阶段、目标阶段、冒泡阶段

w3c规范

语法:element.addEventListener(event,funvtion,useCapture)

event:(必需)事件名,支持所有dom事件

function:(必需)指定事件触发是执行的函数

useCapture:(可选)指定事件是否在捕获或冒泡阶段执行。ture,捕获。false,冒泡。默认false

document.getElementById("btn1").addElementListener("click",hello);
function hello() {
   alert("hello world!")
}

IE标准

语法:element.attachEvent(event,function) 

event:(必需)事件类型,需要加“on”,如:onclick

function:(必需)指定要事件触发时执行的函数

document.getElementById("btn2").attachEvent("onclick",hello);
function hello() {
  alert("hello world")
}

可以绑定多个事件,常规的事件绑定值执行最后绑定的事件。可以解除绑定事件removeEventListener()

 封装事件监听

//绑定监听事件
function addEventHandler(target,type,fn) {
   if(target.addEventListener) {
      target.addEventListener(type,fn);
   }else{
      target.attachEvent("on"+type,fn);
   }
}
//移除监听事件
function removeEventHandler(target,type,fn){
  if(target.removeEventListener){
    target.removeEventListener(type,fn);
  }else{
    target.datachEvent("on"+type,fn)
  }
}

三、事件委托

事件委托就是利用冒泡的原理,把事件加在父元素或者祖先元素上,触发执行结果

var btn = document.getElementById("btn")
ducument.onclick = function() {
  event = event || window.event;
  var target = event.target || event.srcElement;
  if(target == btn ) {
    alert(btn1.value)
  }
}

可以用jq的live(),delegate(),bind(),on()

window.onload = function(){
  var oUl = document.getElementById("ul1");
  oUl.onclick = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    if(target.nodeName.toLowerCase() == 'li'){
            alert(123);
         alert(target.innerHTML);
    }
  }
}

猜你喜欢

转载自www.cnblogs.com/blancher/p/10599629.html