一个妹子总结的文章,思路非常清晰,再配合官网的解释就可以了。
最好带着下面👇几个问题去看。如果你看完一遍没看懂没关系,先去吃饭hhhhh,有些地方再看一遍就懂了。也可以再搜一下网上的文章辅助理解。

Node在poll阶段的注意点有哪些?

  1. 首先poll阶段执行的是I/O操作的回调函数。比如readFile的回调
  2. node文档中说 event loop在 poll阶段如果有预设的setImmediate,那poll阶段将结束,进入check阶段。如果没有,event loop将阻塞在此阶段等待。并且此阶段会有一个检查机制,检查timer队列是否为空(这里的检查机制就像这个阶段的名字一样,是轮询去做的吗?)如果这时候进入一个新的I/O的回调,应该是进入下一轮tick的poll阶段。如果这里的回调需要很久才能计算完,那么系统会一直在这里等待,相当于卡死了。
// 可以试一下下面的结果是啥。
const fs = require('fs')

setTimeout(() => {
  console.log('timeout')
}, 2000)

fs.readFile('./test.md', 'utf-8', () => {
  console.log(1111)
  let a = 1
  setImmediate(() => {
    console.log('timeout')
  })
  while (a < 2) {}
})

fs.readFile('./test.md', 'utf-8', () => {
  console.log(2222)
})

setTimeout(() => {}, 0)和setImmediate(() => {})在哪两种情况下的运行情况不同,分别是怎样的?

  1. 在node刚执行的时候,如果机器性能较好,可能会导致setTimeout的回调到1毫秒(网上的文章说V8源码在setTimeout第二个参数为0的时候强制改为1)的时候已经Event loop已经走到了check层,也就是执行setImmediate回调函数的地方。那这时就会先执行setImmediate,如果机器性能较差,过了好几毫秒才开始走Event loop,那此时按照Event loop的顺序,就会先走timer层,就是先执行timeout的回调。这种情况下就会有两种结果。
setTimeout(() => {
  console.log('timeout')
}, 0)

setImmediate(() => {
  console.log('immediate')
})
  1. 第二种情况就是在poll层检测到有setImmediate,并且当前层队列内的任务都执行完了。那就会进入下一层check层。
const fs = require('fs')

fs.readFile('test.txt', () => {
  console.log('readFile')
  setTimeout(() => {
    console.log('timeout')
  }, 0)
  setImmediate(() => {
    console.log('immediate')
  })
})

浏览器和Node Event loop的差异?

Node中的microtask在每个阶段(一共6个)之间都会执行,浏览器是每个task之间执行。

timer里放的是回调函数而不是setTimeout本身?是什么时候放进去的,时间到了再放还是执行到setTimeout这句就放?

是执行到setTimeout这句就放,放的是回调函数。

下面这段代码怎么执行?换成setImmediata有什么区别

const fs = require('fs')
const starttime = Date.now()
let endtime

fs.readFile('text.txt', () => {
  endtime = Date.now()
  console.log('finish reading time: ', endtime - starttime)
})

let index = 0

function handler () {
  if (index++ >= 1000) return
  console.log(`nextTick ${index}`)
  process.nextTick(handler)
  // console.log(`setImmediate ${index}`)
  // setImmediate(handler)
}

handler()

按目前实验来看是setImmediate的回调函数不会都在当前loop的check阶段执行完。会被推迟到下一轮乃至下下轮。

可以试下
setTimeout(() =>{console.log('~~~')}, 5)
setTimeout(() =>{console.log('~~~')}, 15)
setTimeout(() =>{console.log('~~~')}, 25)
setTimeout(() =>{console.log('~~~')}, 35)
setTimeout(() =>{console.log('~~~')}, 55)

都会穿插在setImmediate的回调函数中执行,说明会一次次进入到timer阶段。