浏览器中存在两个任务队列,⼀个是宏任务⼀个是微任务。但是在NodeJS中⼀共存在六个事件队列,timers,pendingcallbacks,idle prepare,poll,check,close callbacks。每⼀个队列⾥⾯存放的都是回调函数callback。这六个队列是按顺序执⾏的。每个队列负责存储不同的任务。
timer⾥⾯存在的是setTimeout与setInterval的回调函数pending callback是执⾏操作系统的回调,例如tcp,udp。idle 和 prepare只在系统内部进⾏使⽤。⼀般开发者⽤不到poll执⾏与IO相关的回调操作check中存放setImmediate中的回调。close callbacks执⾏close事件的回调。
在Node中代码从上到下同步执⾏,在执⾏过程中会将不同的任务添加到相应的队列中,⽐如说setTimeout就会放在timers中,如果遇到⽂件读写就放在poll⾥⾯,等到整个同步代码执⾏完毕之后就会去执⾏满⾜条件的微任务。可以假想有⼀个队列⽤于存放微任务,这个队列和前⾯的六种没有任何关系。
当同步代码执⾏完成之后会去执⾏满⾜条件的微任务,⼀旦所有的微任务执⾏完毕就会按照上⾯列出的顺序去执⾏队列当中满⾜条件的宏任务。
⾸先会执⾏timers当中满⾜条件的宏任务,当他将timers中满⾜的任务执⾏完成之后就会去执⾏队列的切换,在切换之前会先去清空微任务列表中的微任务。
所以微任务执⾏是有两个时机的,第⼀个时机是所有的同步代码执⾏完毕,第⼆个时机队列切换前。注意在微任务中nextTick的执⾏优先级要⾼于Promise,这个只能死记了。
setTimeout(() => { console.log('s1');})
Promise.resolve().then(() => { console.log('p1');})
console.log('start');process.nextTick(() => { console.log('tick');})
setImmediate(() => { console.log('st');})
console.log('end');// start end tick p1 s1 stsetTimeout(() => { console.log('s1');
Promise.resolve().then(() => { console.log('p1'); })
process.nextTick(() => { console.log('t1'); })})
Promise.resolve().then(() => { console.log('p2')})
console.log('start');
setTimeout(() => { console.log('s2');
Promise.resolve().then(() => { console.log('p3');
})
process.nextTick(() => { console.log('t2'); })})
console.log('end');
// start end p2 s1 s2 t1 t2 p1 p3
Node与浏览器事件环执⾏是有⼀些不同的。
⾸先任务队列数不同,浏览器⼀般只有宏任务和微任务两个队列,⽽Node中除了微任务队列外还有6个事件队列。
其次微任务执⾏时机不同,不过他们也有相同的地⽅就是在同步任务执⾏完毕之后都会去看⼀下微任务是否存在可执⾏的。对浏览器来说每当⼀个宏任务执⾏完成之后就会清空⼀次微任务队列。在Node中只有在事件队列切换时才会去清空微任务队列。
最后在Node平台下微任务执⾏是有优先级的,nextTick优先于Promise.then, ⽽浏览器中则是先进先出。
setTimeout(() => {
console.log('timeout');})
setImmediate(() => {
console.log('immdieate');})
在Node中时⽽会先输出timeout时⽽会先输出immdieate,这是因为setTimeout是需要接收⼀个时间参数的,如果没写就是⼀个0,我们都知道⽆论是在Node还是在浏览器,程序是不可能真的是0,他会受很多的因素影响。这取决于运⾏的环境。
如果setTimeout先执⾏就会放在timers队列中,这样timeout就会先输⼊,如果setTimeout因为某些原因后执⾏了,那么check队列中的immdieate就会先执⾏。这就是为什么时⽽输出timeout时⽽输出immdieate。
const fs = require('fs');fs.readFile('./a.txt', () => { setTimeout(() => {
console.log('timeout'); }, 0)
setImmediate(() => {
console.log('immdieate'); })})
这种情况就会⼀直先输出immdieate后输出timeout,这是因为,代码执⾏的时候会在timers⾥⾯加⼊timeout, 在poll中加⼊fs的回调,在check中加⼊immdieate。fs的回调执⾏结束之后实在poll队列,队列切换的时候⾸先会去看微任务,但是这⾥没有微任务就会继续向下,下⾯就是check队列⽽不是timers队列,所以poll清空之后会切换到check队列,执⾏immdieate回调。到此这篇关于带你了解NodeJS事件循环的⽂章就介绍到这了,更多相关NodeJS事件循环内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
因篇幅问题不能全部显示,请点此查看更多更全内容