一,了解异步和单线程
js从最初设计就是单线程语言。
单线程就意味着不存在异步,只能从上而下的执行代码。js在同一时间只能执行一段代码,如果代码阻塞,就得一直等下去。
因此事件循环(EventLoop)让js拥有了异步的能力。
二,js的事件循环机制
2.1 任务队列
因为js是单线程的语言,所有的任务都在一个线程上执行,这些任务(指每一行代码)排成了一队,形成的队列,就叫做任务队列。
因此任务队列都是按照先进先出的规则,前面的任务执行完成后,再执行下一个任务。
2.2 同步任务
同步任务就是按照任务队列从上到下连贯性的执行,按照先进先出的规则。
2.3 异步任务
js的异步任务可以理解为一个任务不是连续执行的,而是拆成两次执行,第一次执行一部分,然后等准备好后再执行第二部分(也称回调),这种执行方式不会导致线程的阻塞,因此成为异步任务。
这个异步的正是通过事件循环机制(EventLoop)实现的。
2.4 宏任务
事件循环是一个队列,他由宏任务和宏任务执行时产生的所有微任务组成。
因此根据任务队列中的任务不同,分为了宏任务和微任务。
常见的宏任务有:
script整体代码、setTimeout、setInterval、setImmediate(nodejs的)
2.5 微任务
由上可知,微任务是宏任务的组成部分,并非和宏任务并列。
常见的微任务有:
promise中的then、process.nextTikc(nodejs)
特点:
- 宏任务队列只有一个,而每个宏任务都有一个微任务队列。每轮循环都是由一个宏任务队列和多个微任务队列组成。
- 首先,执行第一个宏任务(全局script),产生的宏任务和微任务都到各自的任务队列中,执行完script后,清空所有的微任务队列,进入下一个循环。
三,事件流
3.1 概念
事件:js和html的交互,就是通过事件完成的。事件就是浏览器自身执行的一些动作,比如onclick、onmouseover等。
事件流:DOM(文档对象模型)的结构是树形结构,当一个html元素产生一个事件时,该事件会在当前元素节点到根节点之间按照特定的顺序传播,路径所经过的所有节点都会接收到这个事件,这个传播的过程称为DOM事件流。
事件流的3个阶段:
(1)捕获阶段:开始从文档的根节点流到目标对象,目的为捕获事件
(2)目标阶段:在目标对象上触发(通常为捕获阶段的结束之后、冒泡阶段的开始之前)
(3)冒泡阶段:将目标元素的绑定事件结果返回给浏览器根节点
3.2 事件冒泡
概念:事件从最深的节点开始,逐步向上传播事件。
阻止事件冒泡的方法:通过调用事件对象的 stopPropagation 方法、return false方法
特点:stopPropagation方法只能阻止事件的冒泡,不能阻止浏览器的默认行为
3.3 浏览器的默认行为
概念:网页的每个元素,都有自己的默认行为,例如点击链接会跳转
阻止默认行为的方法:通过调用event.preventDefault()方法、return false方法
特点:event.preventDefault()方法只能阻止事件的默认行为,不能阻止事件的冒泡
3.4 事件委托/事件代理
概念:事件委托,也称为事件代理。就是利用了事件冒泡,只指定一个事件处理程序(例如onclick),而不必为每个可点击的元素分别添加事件处理。
作用:可以通过addEventListener方法为同一个元素注册不同的事件。可以将事件分为事件捕获和事件冒泡
addEventListener(type,listener,useCapture)
- type: 必须,String类型,事件类型
- listener: 必须,函数体或者JS方法
- useCapture: 可选,boolean类型。指定事件是否发生在捕获阶段。默认为false,事件发生在冒泡阶段
优点:
减少事件注册,节省内存使用;
可以实现当新增子对象时,无需再次动态绑定事件。
缺点:
如果DOM嵌套太深,事件大量冒泡会导致性能损失
注意:
事件委托并不代表委托给越顶层的元素越好。因为越顶层的元素,传播链越长,事件的冒泡过程就越耗时。