啊 ,又是个笔/面试常考题,最近投简历面试、笔试被问了无数次了。

1、概念

由于 JavaScript 是一门单线程语言, 所有的任务都只能在一个线程上执行。JS 中的任务分为同步任务和异步任务,同步任务会在主线程上依次执行,而异步任务会被放入一个任务队列中等待,等待主线程中的同步任务执行完毕之后,再根据事件循环机制去执行异步任务。(EventLoop事件循环机制,我在之前的博客中有讲述,在这就不细述了)

但异步任务,又可以细分为宏任务和微任务两种,微任务的执行优先级大于宏任务的执行优先级。每次执行异步任务,到要先检查异步任务中是否有微任务,如果有,则先执行所有微任务,再去执行宏任务。如果没有微任务,则先执行一个宏任务,当执行结束后,再去检查该宏任务有无产生新的微任务要执行,有则先去执行微任务,没有则再执行一个宏任务…

js 微任务和宏任务 消息队列 js宏任务与微任务_javascript

2、常见的宏任务和微任务
常见的宏任务:

① 整体代码 script

② setTimeout 和 setInterval

③ node专属的 setImmediate

④ 浏览器专属的 requestAnimationFrame

常见的微任务:

① Promise.then/.catch/.finally(要注意 Promise(function{ }) 中的代码属于同步代码)

② node专属的process.nextTick(优先级大于①)

3、案例代码

这又一个很重要的注意点:宏任务和微任务是由层级概念的,如果在一个宏任务内部定义了一个微任务,这个微任务就比宏任务要低一个层级,那么就必须等待高一级的宏任务执行后,这个微任务才能被执行。

如果你能把下面这个代码捋清楚,那么你就算是理解了宏任务和微任务:

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 3 5 9 11 10 12
整体思路:

① 第一轮先执行同步代码,输出:1 7 ,然后执行微任务,输出:6 8 ,最后执行一个宏任务 输出:2 4 ,并且创建两个微任务。

② 第二轮,先执行第一个宏任务创建的微任务,输出:3 5。然后执行第二个宏任务,输出: 9 11。并创建两个微任务。

③ 第三轮,执行第二个宏任务创建的微任务,输出:10 12,结束。