一个妹子总结的文章,思路非常清晰,再配合官网的解释就可以了。
最好带着下面👇几个问题去看。如果你看完一遍没看懂没关系,先去吃饭hhhhh,有些地方再看一遍就懂了。也可以再搜一下网上的文章辅助理解。
Node在poll阶段的注意点有哪些?
- 首先poll阶段执行的是I/O操作的回调函数。比如readFile的回调
- 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(() => {})在哪两种情况下的运行情况不同,分别是怎样的?
- 在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')
})
- 第二种情况就是在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阶段。