浏览器的事件循环机制
同步代码在主进程中直接执行,异步函数先放在异步队列中,待同步函数执行完毕后,轮询执行异步队列的任务
异步队列的任务又分为宏任务和微任务
(1)宏任务
- script 整体代码
- setTimeout、setInterval、setImmediate
- I/O
- ui render
(2)微任务
- process.nextTick
- promise.then
- async/await(实则就是 promise)
JS异步机制由事件循环和任务队列构成,JS本身是单线程语言
遇到异步操作时,将其放在异步队列里,等主线程的执行栈空的时候就去执行异步队列里的任务。每执行一次宏任务后,执行完任务队列里所有的微任务,再进行下一个宏任务,如此循环
nodejs 的事件循环机制
两者最大的区别在于浏览器中的微任务是在每个相应的宏任务中执行的,而 node 中的微任务是在不同阶段之间执行的
libuv 里面的 uv_run 函数实现了事件循环的整个过程(6 个阶段):
(1)timers
- setTimeout
- setInterval
(2)IO callback 事件回调阶段
- eventEmitter
(3)idle, prepare 闲置阶段
- 系统内部使用
(4)poll 轮询阶段
- 检索新的 I/O 事件,执行与 I/O 相关的回调(几乎所有情况下,除了关闭的回调函数,那些由计时器和 setImmediate() 调度的之外),其余情况 node 都在恰当的时候在这阻塞
- incoming data 输入数据
- fs.readFile
(5)check 检查阶段
- 直接执行 setImmediate
(6)close callback 关闭时间的回调
- 如果一个 socket 或 handle 被突然关掉,close 事件将在这个阶段被触发,否则将通过 process.nextTick() 触发
日常开发中,绝大部分异步任务都是在 poll、check、timers 这三个阶段处理