天天看点

js的三大事件、事件移除、事件循环机制

什么是事件,三种事件模型

事件是用户操作网页时发生的交互动作或者网页本身的一些操作。

现代浏览器一共有三种事件模型:

  • DOM0 级事件模型,这种模型不会传播,所以没有事件流的概念,但是现在有的浏览器支持以冒泡的方式实现,它可以在网页中直接定义监听函数,也可以通过 js 属性来指定监听函数。所有浏览器都兼容这种方式。

    直接在 dom 对象上注册事件名称,就是 DOM0 写法

  • IE 事件模型,在该事件模型中,一次事件共有两个过程,事件处理阶段和事件冒泡阶段。

    事件处理阶段会首先执行目标元素绑定的监听事件。

    然后是事件冒泡阶段,冒泡指的是事件从目标元素冒泡到document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。

    attachEvent就是IE事件模型

    ,attachEvent用来添加监听函数,可以添加多个监听函数,会按顺序依次执行。
  • DOM2 级事件模型,在该事件模型中,一次事件共有三个过程,

    第一个过程是事件捕获阶段。捕获指的是事件从 document 一直向下传播到目标元素,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。后面两个阶段和 IE 事件模型的两个阶段相同。

    addEventListener 就是DOM2级事件模型

三大事件(鼠标事件、键盘事件、html事件)

1、鼠标事件

  • click:单击
  • dblclick:双击
  • mousemove:鼠标移动
  • mousedown:鼠标按下
  • mouseup:鼠标抬起
  • mouseover:鼠标悬浮
  • mouseout:鼠标离开
  • mouseenter:鼠标进入
  • mouseleave:鼠标离开

2、键盘事件

  • keydown:按键按下
  • keyup:按键抬起
  • keypress:按键按下抬起

3、HTML事件

  • load:文档加载完成
  • select:被选中的时候
  • change:内容被改变
  • focus:得到光标
  • blur:失去光标
  • resize:窗口尺寸变化
  • scroll:滚动条移动

事件委托机制

事件委托指的是,不在事件的发生地设立监听函数,而是在事件发生地的父元素或者祖先元素设置监听器函数,这样可以大大提高性能,因为可以减少绑定事件的元素,比如:

<ul>
  <li></li>
  <li></li>
  <li></li>
</ul>
           

你要给li元素绑定click事件,

使用事件委托机制的话,就只需要给ul绑定click事件就行了,

这样就不需要给每个li’绑定click事件,减小内存占用,提高效率。

事件的移除

事件的注册方式对应其移除方式

1、 el.onclick = null

var el = document.getElementById("btn");
//事件注册
 el.onclick = function(event){  
     alert(id); 
     el.onclick = null;   //事件删除
 }
           

2、el.removeEventListener(type,fn,false); //这里 fn 必须是原有绑定的函数,否侧解除无效

var div = document.getElemetById('id');
div.addEventListener('click',test,false);
function test(){
 console.log('remove click');
}
div.removeEventListener('click',test,false);
           

事件循环机制

0、背景 (

重点!!!!

JavaScript 在设计之初便是单线程,即指程序运行时,只有一个线程存在,同一时间只能做一件事

为了解决单线程运行阻塞问题,JavaScript用到了计算机系统的一种运行机制,这种机制就叫做

事件循环(Event Loop)

重点!!!!

既然JS是单线程的,那么诸如onclick回调,setTimeout,Ajax这些异步都是怎么实现的呢?

是因为js在浏览器中执行,而

浏览器或node是多线程

的,为了解决js单线程运行阻塞问题,

浏览器搞了几个异步线程去辅助JS主线程的运行

浏览器有很多线程,例如:
1、GUI 渲染线程
2、JS 引擎线程
3、定时器触发线程 (setTimeout)
4、浏览器事件线程 (onclick)
5、http 异步线程
6、EventLoop轮询处理线程
......
           

那么主线程与这些异步线程之间的运行机制,就是

事件循环机制

为什么要把js设计成单线程 ?

因为JavaScript 初期作为一门浏览器脚本语言,通常用于操作 DOM ,如果是多线程,一个线程进行了删除 DOM ,另一个添加 DOM,此时浏览器该如何处理?

1、是什么

前言:

JavaScript 有一个

主线程和调用栈

,所有的任务最终都会被放到调用栈等待主线程执行。

主线程之外存在一个

任务队列

,任务队列中就是异步任务的回调,最终这些回调会被调用栈读取后放入主线程中运行。

Event Loop 具体过程如下:

1.1, js在执行代码时,由上至下进行解析;

1.2, 首先,遇到任务,判断该任务是同步还是异步任务;

1.3, 同步任务会被放在调用栈中,按照顺序等待主线程依次执行。

1.4, 如果是异步任务,

开启异步线程,执行异步任务

( 而主线程继续执行同步代码 )

异步任务 执行完后,将其回调函数 放入

相应的任务队列

(Event Queue)中,而任务队列分为宏任务队列与微任务队列,等待任务的执行。

1.5,调用栈内的任务执行完毕时,此时

主线程处于空闲状态

,会去 任务队列 读取任务,再把它推入主线程执行。(读取任务队列中的任务时,优先读取微任务,后读取宏任务),执行完一个再去 任务队列读取异步任务,把任务放到主线程中执行,如此循环,这就是 JavaScript 的运行机制,称为

事件循环机制(Event Loop)

总结 js执行顺序: 同步函数 ===》微任务 ===》 宏任务

总结:事件循环机制如下:

1、同步代码,直接执行

2、 异步代码,开启异步线程,执行异步代码,执行完毕后,将其回调函数,放入任务队列中。

3、待同步函数执行完毕,轮询执行任务队列的函数

2、异步任务有哪些,用浏览器的哪个异步线程执行

  • 1、定时任务:setTimeout、setInterval ---------

    浏览器定时器线程

  • 2、网络请求:ajax请求、动态img加载 ---------

    浏览器http异步线程

  • 3、DOM绑定的事件:dom事件 ---------

    浏览器事件线程

  • 4、ES6中的promise.then中的函数
Promise 构造函数是同步执行的,promise.then 中的函数是异步执行的。

3、异步线程何时被放入任务队列?

  • 1、DOM绑定的事件-------- 由

    浏览器事件线程

    处理,事件触发时,回调函数添加到任务队列中;
  • 2、定时任务:---------由

    浏览器定时器线程

    处理,时间到达时,回调函数添加到任务队列中;
  • 3、网络请求 ----------- 由

    浏览器http异步线程

    处理,网络请求返回后,回调函数添加到任务队列中。
ajax加载完成,即ajax什么时候success,就什么时候把ajax中的函数放入到异步队列中
异步任务又分为 宏观任务 、微观任务

4、 异步任务分类: 宏观任务、微观任务

  • 宏观任务包含以下几类

    定时器----setTimeout、setInterval、

    DOM绑定的事件、

    异步Ajax请求

    文件操作

  • 微观任务包含以下几类—常用的ES6新增的方法

    Promise.then、

    async/await (实际上是promise+generator的语法糖)

    Generator

【参考链接】:https://www.cnblogs.com/yugege/p/9598265.html

【参考链接】:https://mp.weixin.qq.com/s/9iN7XR1PwXfua8SrabOi5w

继续阅读