node中我对Event Loop和宏任务,微任务的理解

 

 开始理论部分

1.任务队列和主线程

任务分为两种,一种同步任务,一种是异步任务。同步任务会在主线程执行

同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。

node中我对Event Loop和宏任务,微任务的理解_第1张图片

那又什么是宏任务和微任务呢,单拿出来同步任务,也分宏任务和微任务。执行顺序就是先执行宏任务,再执行微任务。

在异步队列里是不是也有宏任务和微任务,那是当然,执行顺序也是一样。现在我们只要记住谁是宏任务,谁是微任务,谁在前谁在后就行了

宏任务

一般普通的代码都是宏任务,一步一步往下执行。for循环,声明变量,声明函数等等

 

# 浏览器 Node
setTimeout
setInterval
setImmediate x
requestAnimationFrame x

 

微任务

# 浏览器 Node
process.nextTick x
MutationObserver x
Promise.then catch finally

 

node中我对Event Loop和宏任务,微任务的理解_第2张图片

 

我下边举个例子,一边看这个例子,一边看我上边列出来那个宏任务和微任务那个表

setTimeout(() => {
    //执行后 回调一个宏事件
    console.log(1)
}, 0)
console.log(2);

new Promise((resolve) => {
    console.log(3);
    resolve()
}).then(() => {
    console.log(4);
}).then(()=>{
    console.log(5);
})
//node执行结果 2 3 4 5 1

首先千万不要把异步队列和这个宏任务微任务搞混,认为异步的就微任务,那是没理解透。

分析上边代码。

1. 代码从上往下执行,先遇见一个setTimeout,一看是个微任务,你先等等,看看有没有宏任务要执行。
 2. 发现有,console.log(2);他是这个代码最外层中唯一宏任务,不用考虑,执行掉。
 ------->  输出 2
 3. 剩下一个Promise和setTimeout,都是微任务,谁在前边谁先执行。
4. 解析到setTimeout,发现是个异步任务,就给他扔到异步队列里去了,等我们主线程完事再管你。
 5. 然后就是Promise执行了,这个console.log(3);就被执行了。  
  -------->  输出  3
 6. 当程序发现了then,这又是个异步任务啊。那你也去异步队列里去排队去。
 7. 这个时候你会想,我懂了。然后就是1,4,5,可是结果却是4,5,1 //  console.log(1)这个时候有想法了,怎么的我们都是console.log你俩凭啥在我前边,而且我就算是排队也是我先输出啊
 这个问题出在这里。异步队列中的这个setTimeout里的回调虽然排队排第一个了,但是时间还没到。
HTML5标准规定了setTimeout()的第二个参数的最小值(最短间隔),不得低于4毫秒,如果低于这个值,就会自动增加
也即是说,第一次主线程空了去轮询异步队列时,setTimeout时间未到.也就是说看着是0实际上还是有时间的,所以就出现这个问题了

------>继续 输出4 ,5 , 1

除了setTimeout和setInterval这两个方法
Node.js还提供了另外两个与任务队列有关的方法:process.nextTick和setImmediate。
process.nextTick方法可以在当前"执行栈"的尾部----下一次Event Loop(主线程读取"任务队列")之前----触发回调函数。
也就是说,它指定的任务总是发生在所有异步任务之前。
setImmediate方法则是在当前"任务队列"的尾部添加事件,也就是说,它指定的任务总是在下一次Event Loop时执行

so利用下边的案例,就能彻底解决疑惑


console.log('1');
setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})

process.nextTick(function() {
    console.log('6');
})

new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

先公布答案:

执行结果是:1,7,6,8,2,4,9,11,3,10,5,12

// 执行结果是:1,7,6,8,2,4,9,11,3,10,5,12
// 分析:  1. 首先看,主程序,先执行宏任务,console.log(1);
// -------  1
// 2. 然后就是执行微任务 第一个setTimeout回调扔进异步队列等着,process.nextTick当执行异步事件队列的时候第一个执行,然后Promise执行
// -------  7
// 3. 然后.then扔进异步时间队列,然后遇到setTimeout,再次扔进队列
// 4. 主进程执行完毕,执行异步时间队列,所以process.nextTick下边的6被执行
// -------  6
// 然后执行then里的内容,因为setTimeout的时间还没到。(前边有讲过为什么)
// -------  8
// 5. 然后第一个setTimeout里的回调开始执行,也分宏任务和微任务的方式执行,同时也是遇到异步就送到异步队列中去。等待主线程完成。
// 6. 也就是说第一个setTimeout里的回调函数里的主线程全部执行完,
// -------- 2
// -------- 4
// 7. 然后主线程没东西了,去异步线程,此时最后一个setTimeout也被推到最前边来了。然后也按宏任务,微任务等等玩法
// -------  9  
// -------- 11
// 剩下的不用再说了。执行异步队列了。按顺序执行就是了。 3,10,5,12

弄懂他,就算是有这类的面试题你也不怂啊

 

你可能感兴趣的:(Node)