事件轮循机制
Event Loop
(事件循环)是 JavaScript 中非常重要的概念,它是 JavaScript 执行模型的核心部分。为了理解事件循环,我们需要从 JavaScript 的单线程特性入手。
1. 单线程模型
js是单线程的, 这意味着它一次只能执行一个任务 但是现代需要处理大量异步操作(处理用户输入IO, 网络请求ajax,xhr 定时器setTimeout setInterval等)这些任务都需要排队等待执行. 事件循环就是解决这个问题的.
2. 异步操作
在JavaScript中, 异步操作时通过回调函数callback Promise 或 async/await 实现的.事件循环本质上并不是我们通常理解的"循环"那种反复执行的操作, 而是一个不断检查和分配任务的过程.
3. 事件循环是如何工作的?
事件循环可以分为以下几个步骤:
-
执行栈(Call Stack):
- JavaScript 代码会依次进入执行栈(栈是 LIFO 结构),并依次执行。
- 当执行栈为空时,事件循环会去检查 任务队列(Task Queue)中是否有等待执行的任务。
-
任务队列:
- 异步操作(比如
setTimeout
、事件监听、网络请求等)会将回调函数添加到任务队列中。
- 异步操作(比如
-
事件循环:
- 事件循环不断地从任务队列中取出任务,并将其推送到执行栈中去执行。
-
宏任务和微任务:
- 宏任务:通常是一些较大粒度的任务,例如
setTimeout
、I/O 操作、用户输入等。 - 微任务:例如
Promise
的.then
回调、MutationObserver
等。微任务会在宏任务之前执行,保证异步操作的优先级更高。
- 宏任务:通常是一些较大粒度的任务,例如
4. 为什么提出事件循环?
事件循环的提出是为了使 JavaScript 能够在单线程模型下高效执行异步操作. 在没有事件循环之前, 所有的异步操作都需要自己管理线程, 复杂的逻辑和多个异步操作会导致代码混乱和性能问题. 事件循环让我们可以再 JavaScript 中 顺利的处理多个异步任务, 并且保证UI的响应性.
5. 举个例子
来看一个例子,假设我们有如下代码:
console.log('start');setTimeout(() => {console.log('timeout');
}, 0);Promise.resolve().then(() => {console.log('promise');
});console.log('end');
输出顺序是:
start
end
promise
timeout
为什么是这个顺序呢?
console.log('start')
和console.log('end')
会直接执行,因为它们是同步任务。setTimeout
是一个宏任务,它会被放入任务队列中,等待主线程执行完同步任务后才会执行。Promise.resolve().then()
是微任务,它的回调会被放到微任务队列中,微任务队列中的任务会在每次宏任务执行之前执行。
这就是事件循环的工作机制。
参考https://jakearchibald.com/