DOM事件
- 事件概念:事件是文档或浏览器中发生的交互行为的响应。
- 事件流:分为三个阶段:
- 捕获阶段:事件从根节点开始,逐级向下传播至目标节点。
- 目标阶段:事件在目标节点上被处理。
- 冒泡阶段:事件从目标节点逐级向上传播至根节点。
事件模型
-
原始事件模型(DOM0级事件)
- 特点:跨浏览器兼容性好,事件绑定快速,仅支持冒泡,同类型事件只能绑定一个。
- 绑定方式:HTML属性(如
onclick
)、JavaScript属性赋值。 - 解绑方式:将事件处理器设置为
null
。
-
标准事件模型(DOM2级事件)
- 特点:允许添加多个同类型事件,可以控制事件在捕获/冒泡阶段执行。
- 绑定方式:
addEventListener
、removeEventListener
(解绑时需传入相同的函数引用和触发时机)。
事件委托
- 使用场景:当多个子节点需要注册相同类型的事件时,可以在父节点上注册,利用事件冒泡。
- 优点:减少内存使用,减少事件注册的工作量。
浏览器事件
- 事件循环:JavaScript 引擎是单线程的,通过事件循环实现非阻塞。
- 任务种类:
- 同步任务:直接在主线程中执行的任务。
- 异步任务:注册回调函数后放入事件队列中等待执行。
异步任务
- 微任务:
Promise.then
、MutationObserver
、process.nextTick
(Node.js)。 - 宏任务:整体
<script>
代码、setTimeout
/setInterval
、用户触发的 DOM 事件、网络请求、I/O 事件(Node.js)、setImmediate
(Node.js)。
async/await
async
:声明异步函数,返回值为Promise
对象。await
:在async
函数中使用,等待表达式执行完成后继续执行后续代码。
Node.js 事件循环
事件循环机制
Node.js 的事件循环是基于 libuv
库实现的,它为 Node.js 提供了一个异步非阻塞I/O的环境。事件循环负责调度和执行所有的回调函数。
异步任务分类
在 Node.js 中,异步任务分为微任务(microtasks)和宏任务(macrotasks)。
微任务(Microtasks)
- nextTick queue:这是最高优先级的队列,用于
process.nextTick
方法的回调。 - other queue:包含其他微任务,如
Promise
的.then()
方法。
宏任务(Macrotasks)
- timer queue:定时器任务,如
setTimeout
和setInterval
。 - poll queue:轮询阶段,用于执行 I/O 操作,如文件读写和网络请求。
- check queue:检查阶段,用于执行
setImmediate
方法的回调。 - close queue:关闭阶段,如关闭网络连接时的回调。
事件循环的执行顺序
- 执行所有微任务:在执行完一个宏任务后,事件循环会检查微任务队列,并执行其中的所有任务,直到队列为空。
- 执行一个宏任务:事件循环从当前宏任务队列中取出一个任务执行。
- 进入下一个阶段:事件循环进入下一个阶段,并执行该阶段对应的宏任务队列中的任务。
特殊注意点
- 快照机制:在事件循环的每个阶段开始时,会对宏任务队列进行快照,然后按照快照队列的顺序执行任务。在执行过程中,新加入的任务不会影响当前的快照。
- 微任务执行顺序:首先执行
nextTick queue
中的所有回调,然后执行other queue
中的所有回调。 - 宏任务队列的遍历顺序:按照
timer
、poll
、check
、close
的顺序进行。 - 定时器精度:如果
setTimeout
或setInterval
设置的延迟为 0ms,实际上会被 Node.js 强制设置为 1ms。