事件循环、宏任务、微任务一网打尽(附超多经典面试题)( 五 )


  • 如果 poll 队列 为空 时 , 会有两件事发生
    • 如果有 setImmediate 回调需要执行 , poll 阶段会停止并且进入到 check 阶段执行回调
    • 如果没有 setImmediate 回调需要执行 , 会等待回调被加入到队列中并立即执行回调 , 这里同样会有个超时时间设置防止一直等待下去(2)如果 设置了 timer 的话且 poll 队列为空 , 则会判断是否有 timer 超时 , 如果有的话会回到 timer 阶段执行回调 。

    5.check 检测:
    (1)setImmediate 回调函数在这里执行;(2)注意并不是马上执行 , 而是当事件循环poll中没有新的事件处理时才执行这部分;
    6.close callbacks
    执行一些关闭的回调函数 , 如:socket.on(‘close’, …) 。
    三.process.nextTick
    这个函数其实是独立于 Event Loop 之外的 , 它有一个自己的队列 , 当每个阶段完成后 , 如果存在 nextTick 队列 , 就会清空队列中的所有回调函数 , 并且优先于其他 microtask 执行
    四.nodejs事件循环的一些经典面试题
    1.nodejs中setTimeout 和 setImmediate
    二者非常相似 , 区别主要在于调用时机不同 。 (1)setImmediate 设计在poll阶段完成时执行 , 即第五个check阶段;(2)setTimeout 设计在poll阶段为空闲时 , 且设定时间到达后执行 , 但它在第一个timer阶段执行
    (1)对于以上代码来说 , setTimeout 可能执行在前 , 也可能执行在后 。 (2)首先 setTimeout(fn, 0) === setTimeout(fn, 1) , 这是由源码决定的;然后进入事件循环也是需要成本的 , 如果准备时间花费大于 1ms 的时间 , 那么在 timer 阶段就会直接执行 setTimeout 回调(3)如果准备时间花费小于 1ms , 那么就是 setImmediate 回调先执行了
    2.上面的代码如果放到fs.readFile的回调中
    结果就是固定的,先是immediate再是timeout
    因为读完文件就是进入到了I/O阶段 , Poll队列为空 , 有setImmediate , poll 阶段会停止并且进入到 check 阶段执行回调 。
    3.同一轮事件循环 , 优先把微任务队列清空再执行宏任务队列
    (1)主代码块输出script start、 script end(2)微任务:promise和nextTick 全都放到poll中 , 一次性全部执行完 , nextTick优先级高 , 所以先打印(3)setTimeout 1ms执行完加到 poll队列 , 去执行;里面的fs.readfile 2放到下一轮;(4)poll队列为空 , 去执行 setImmediate(5)文件读取完成 加入poll队列 , 输出 read file success 和 read file success 2结果:// script start// script end// nextTick callback// promise1// promise4// promise2// promise5// promise3// promise6// setTimeout// setImmediate// read file success// read file success 2
    4.主线程会被阻塞
    (1)setTimeout时间设置0的结果1sleep 3sread file success(2)setTimeout时间设置50ms的结果setTimeout 50ms 的结果read file successsleep 3s