宏任务和微任务

88 阅读4分钟

背景

js是一种单线程语言,只有一条通道,那么在任务多的情况下,就会出现堵塞,这种情况下就产生了多线程,那么就产生了同步任务和异步任务。

  • 同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务,是由js执行栈/回调栈执行的。

  • 异步任务:不进入主线程,而进入任务队列的任务,当主线程中的任务运行完成了,才会从任务队列中取出异步任务,放入主线程中执行。

宏任务和微任务

宏任务和微任务都是异步任务,它们都属于一个队列

  • 宏任务:由宿主环境发起的,比如浏览器、node等,宏任务异步代码有 script (代码块)、setTimeout setInterval (定时器)、 postMessage MessageChannel 以及 Nodejs 环境中的 setImmediate(定时器) ......等等。

  • 微任务:由js引擎发起的,Promise.then(Promise本身同步,只有它里面的then/catch的回调函数是异步的微任务)、Async/AwaitObject.observeMutationObserver 、及Nodejs 环境中的 process.nextTick

任务执行顺序

有人说宏任务先于微任务执行,也有人说微任务先于宏任务执行。

其实,由于整个script本身就是一个大的宏任务,所以在执行任务时,肯定是执行script这个大的宏任务里面的代码,因此我们也可以说是宏任务先于微任务。

但是如果我们忽略script这个大的宏任务,仅仅只是讨论script里包含的任务代码块,那么任务的执行顺序就一定是微任务优先于宏任务。

在这里,我们就先忽略script执行顺序就为:同步任务 ---> 微任务 ---> 宏任务

案例演示:下面代码的执行结果是什么?

console.log(1);
setTimeout(()=>{
    console.log(2);
},0);

const p = new Promise((resolve,reject)=>{
    console.log(3);
    resolve('success');
    console.log(4);
});

p.then((value)=>{
    console.log(value);
});

console.log(5);

我们可以通过开头的理论解释,将上面代码分为同步任务、微任务、宏任务。

哪些属于同步任务、微任务、宏任务 ,如下图:

1.png

分别放入相应的队列里,可以得到以下代码执行的流程图:

2.png

3.png

4.png

最后得到结果是:1、3、4、5、'success'、2

详细讲解宏任务和微任务的区别

首先,宏任务和微任务的执行时机是不同的。

宏任务会在主线程执行完毕后被执行,而微任务会在主线程执行完毕之前立即执行。

其次,宏任务和微任务的优先级也是不同的,在js中,微任务的优先级比宏任务高,也就是说,如果微任务队列和宏任务队列中都有任务需要执行,微任务会先于宏任务执行。

另外,宏任务和微任务对于js事件循环的影响也是不同的,宏任务会触发事件循环,而微任务不会触发事件循环,而是在主线程上的同步任务执行完毕后立即执行。

此外,宏任务和微任务在实际应用中有着不同的用途,宏任务通常用于与浏览器渲染相关的任务,如setTimeout 和 requestAnimationFrame 而微任务通常用于异步操作,如Promise.then 和async/await。

通过理解宏任务和微任务的区别,我们可以更好的优化代码的性能,例如避免在微任务中执行大量耗时的操作。

总之,宏任务和微任务是js中非常重要的概念,对于更好的理解js的执行机制和优化代码性能是非常有帮助的。

小试牛刀

console.log(1);
setTimeout(()=>{
    console.log(2);
    setTimeout(()=>{
        console.log(3);
        setTimeount(()=>console.log(4),0);
        Promise.resolve().then(()=>console.log(5));
    },0);
},0);
console.log(6);

解答:

  • 首先,输出1和6 之后第一个setTimeout中的回调函数执行,输出2。
  • 之后执行第二个setTimeout 中的回调函数,输出3。
  • 然后微任务Promise.resolve()执行输出5。
  • 最后执行第三个setTimeout中的回调函数输出4。

总结

  1. 宏任务会在主线程执行完毕后被执行,而微任务会在主线程执行完毕后之前立即执行。
  2. 宏任务会触发事件循环,而微任务不会触发事件循环,而是在主线程上执行完毕后立即执行。