什么是事件,三种事件模型
事件是用户操作网页时发生的交互动作或者网页本身的一些操作。
现代浏览器一共有三种事件模型:
- DOM0 级事件模型,这种模型不会传播,所以没有事件流的概念,但是现在有的浏览器支持以冒泡的方式实现,它可以在网页中直接定义监听函数,也可以通过 js 属性来指定监听函数。所有浏览器都兼容这种方式。
。直接在 dom 对象上注册事件名称,就是 DOM0 写法
-
IE 事件模型,在该事件模型中,一次事件共有两个过程,事件处理阶段和事件冒泡阶段。
事件处理阶段会首先执行目标元素绑定的监听事件。
然后是事件冒泡阶段,冒泡指的是事件从目标元素冒泡到document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。
,attachEvent用来添加监听函数,可以添加多个监听函数,会按顺序依次执行。attachEvent就是IE事件模型
-
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