概述
事件轮询是计算机系统的一种运行机制,JS采用这种机制,来解决单线程与异步的一些问题。
单线程的问题
- 所有任务都在一个线程下执行,遇到大量任务或耗时任务,就会导致网页假死,无法进行交互
- 并且如果一个任务阻塞了,后续的代码都会被一直搁置
因此就产生了异步的概念,即通过其他线程去完成某些耗时操作,如AJAX、定时器等
- 运行环境会为异步操作提供一个单独的线程,因为不在主线程中执行,所以不会造成阻塞
- 但是异步也导致结果不可预测,无法同步获得结果,只能通过 事件 + 异步回调 的方式
- 但当事件触发时,无法保证 JS 线程是空闲的,异步回调无法立刻执行
而事件轮询机制,解决了上述的问题
- 事件轮询中有个 任务队列,异步任务触发事件时,会将对应的回调添加到这个队列中
- 这就缓存了回调,且队列是有序的,保证了回调正常有序的执行
- 当JS线程空闲时,就会查询任务队列,并逐个执行其中的任务
整体流程

- 运行环境会为异步操作提供单独的线程
- 当异步任务执行完毕后,会触发指定的事件,并将对应事件的回调添加到任务队列中
- JS引擎执行完同步任务,栈空闲时,就会将队列中的回调压入栈中同步执行,以此循环
- 当队列为空时,JS引擎就会等待,直到有新的回调进入队列,然后开启下一个循环
任务队列(task queue)

- 专门用来存放待执行任务的队列,任务:异步任务触发事件时,对应需要执行的异步回调
- 一个JS线程只会拥有一个事件循环,但是可以有多个任务队列,根据任务类型分为两个
- 宏队列(macro-task queue):存放宏任务的队列
- 微队列(macro-task queue):存放微任务的队列
- 轮询顺序:在不同的环境中,两条队列有着不同的轮询顺序
- 浏览器:执行完一个宏任务后,立刻轮询微队列,微任务全部执行完成后,再从宏队列开始轮询
- Node:先轮询宏队列,直到宏队列全部执行完成后,再去轮询微队列
宏任务、微任务
不同队列的任务分为两种
- 宏任务(macro-task):script内的代码,定时器回调,I/O,UI rending
- 微任务(micro-task):promise回调,MutationObserver回调,process.nextTick回调
- 在最新标准中,分别称为 task 和 jobs
如Promise/定时器称之为任务源,它们的事件回调才是任务
**
