js宏任务与微任务详解

js宏任务与微任务详解

  • 0、前言
    • 为什么要区分微任务和宏任务?
    • 微任务和宏任务是怎么执行的?
  • 1、概念
  • 2、示例
    • 2.1 例1
    • 2.2 例2
    • 2.3 例3
    • 2.4 例4
    • 2.5 例5

0、前言

为什么要区分微任务和宏任务?

(1)js是单线程的,但是分同步异步
(2)微任务和宏任务皆为异步任务,它们都属于一个队列
(3)宏任务一般是:script、setTimeout、setInterval、postMessage、MessageChannel、setImmediate(Node.js 环境)
(4)微任务:Promise.then、Object.observe、MutationObserver、process.nextTick(Node.js 环境)
(5)先执行同步再执行异步,异步遇到微任务,先执行微任务,执行完后如果没有微任务,就执行下一个宏任务,如果有微任务,就按顺序一个一个执行微任务

微任务和宏任务是怎么执行的?

执行顺序:先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环直至所有任务执行完毕。

这里容易产生一个错误的认识:就是微任务先于宏任务执行。实际上是先执行同步任务然后在执行异步任务,异步任务是分宏任务和微任务两种的。

1、概念

宏任务:指执行栈中待执行的任务,如计时器,事件回调,http回调等。

微任务:指执行栈清空后立即执行的任务,如Promise的回调函数、process.nextTick、MutationObserver等。

2、示例

2.1 例1

代码如下:

console.log("start");

setTimeout(()=>{
	console.log("setTimeout");
},0);
    
new Promise((resolve,reject)=>{
	for(var i=0;i<5;i++){
    	console.log(i);
    }
    resolve() //修改promise状态为成功
}).then(()=>{
    console.log("promise回调函数");
})

console.log("end");
// start, 0, 1, 2, 3, 4, end, promise回调函数, setTimeout

分析:

1、先执行主线程上的同步代码,输出start
2、遇到setTimeout将其加入到宏任务队列等待执行
3、遇到promise 立即执行,输出 0,1,2,3,4
4、遇到promise的回调函数将其加入到微任务队列
5、执行主线程的同步代码,输出end
6、第一个宏任务队列执行完毕查看存在微任务队列,执行微任务队列中的任务,输出promise的回调函数
7、微任务执行完毕,执行下一个宏任务队列中的任务,输出setTimeout

2.2 例2

代码如下:

console.log(1)
setTimeout(function() {
    console.log(2)
}, 0)
const p = new Promise((resolve, reject) => {
    resolve(4)
})
p.then(data => {
    console.log(data)
})
console.log(3)
//1,3,4,2

分许:

  1. 遇到同步任务console.log(1),输出1;
  2. 遇到setTimeout 异步宏任务,放入宏任务队列中;
  3. 遇到 Promise,new Promise在实例化的过程中所执行的代码都是同步进行的,但由于new Promise没有输出事件,所以接着执行遇到.then;
  4. 执行.then,异步微任务,被分发到微任务Event Queue中;
  5. 遇到同步任务console.log(3),输出3;
  6. 主线程中同步任务执行完,从微任务队列中取出任务到主线程中,p.then 输出4,微任务执行完毕,任务队列为空;
  7. 开始执行宏任务setTimeout 输出2,宏任务队列为空;

2.3 例3

代码如下:

console.log(1)
setTimeout(function() {
    console.log(2)
    new Promise(function(resolve) {
        console.log(3)
        resolve()
    }).then(function() {
        console.log(4)
    })
})
 
new Promise(function(resolve) {
    console.log(5)
    resolve()
}).then(function() {
    console.log(6)
})
 
setTimeout(function() {
    console.log(7)
    new Promise(function(resolve) {
        console.log(8)
        resolve()
    }).then(function() {
        console.log(9)
    })
})
console.log(10)
//1,5,10,6,2,3,4,7,8,9

分析:

  1. 遇到同步任务console.log(1),输出1;
  2. 遇到setTimeout 异步宏任务,放入宏任务队列中;
  3. 遇到 Promise,new Promise在实例化的过程中所执行的代码都是同步进行的,所以输出5,所以接着执行遇到.then;
  4. 执行.then,异步微任务,被分发到微任务Event Queue中;
  5. 遇到setTimeout,异步宏任务;放入宏任务队列中;
  6. 遇到同步任务console.log(10),输出10,主线程中同步任务全部执行完;
  7. 从微任务队列中取出任务到主线程中,输出6;
  8. 在从宏任务队列中取出任务到主线程中,执行第一个setTimeout,输出2,3,4(在宏任务中执行同步,同步,异步微任务);
  9. 在执行第二个setTimeout,输出7,8,9(和8同理);

2.4 例4

代码如下:

console.log('1');
async function async2() {
    console.log('2')
}
async2()
console.log('3');
// 1,2,3

分析:

  1. 遇到同步任务,输出1;
  2. 遇到async await会暂停当前执行,输出2;
  3. 遇到同步任务,输出3.

2.5 例5

代码如下:

console.log('1');
async function async1() {
    await async2();
    console.log('2');
};
async function async2() {
    console.log('3')
}
console.log('4');
async1()

分析:

  1. 遇到同步任务,输出1;
  2. 遇到async await,但函数并未执行;
  3. 遇到同步任务,输出4;
  4. 执行async1,输出3, 2。

你可能感兴趣的:(JavaScript,javascript,前端,开发语言)