js中的微任务和宏任务

因为javascript是一门单线程语言,所以代码的解析执行都要以自上而下的执行,直到任务队列(task queue)的出现,js开始有了异步任务,当一段代码需要稍后执行时,便可以使用异步方案(setTimeout、setInterval、Poromis、Axios、Dom事件)来使指定操作添加到异步任务中。

代码执行流程: 主线程 => 微任务 => 宏任务

宏任务(macroTask)和微任务(microTask)都是异步中API的分类。

  • 宏任务:setTimeout,setInterval,Ajax,requestAnimationFrame,postMessage、网络I/O、文件I/O、用户交互的回调等事件、UI渲染事件(DOM解析、布局计算、绘制)

  • 微任务:Promise,async/await,MutationObserver,process.nextTick

首先我们先来看一段代码,看一下代码的执行顺序。

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

Promise.resolve().then(() => {
	console.log('promise');
		Promise.resolve().then(() => {
			console.log('promise2');
	})
})

console.log('main');

执行顺序是 log(‘main’) log(‘promise’) log(‘promise2’) log(‘setTimeout’);

setTimeout(() => {
	Promise.resolve().then(() => {
		console.log('promise')
	})
},0);

Promise.resolve().then(() => {
	setTimeout(() => {
		console.log('setTimeout')
	},0)
});

console.log('main');

执行顺序是 log(‘main’) log(‘promise’) log(‘setTimeout’);

除了广义的同步任务和异步任务,JavaScript 单线程中的任务可以细分为宏任务和微任务

  1. 宏任务进入主线程,执行过程中会收集微任务加入微任务队列。
  2. 宏任务执行完成之后,立马执行微任务中的任务。微任务执行过程中将再次收集宏任务,并加入宏任务队列。
  3. 反复执行1,2步骤
  4. 宏任务想要执行的话必须要等微任务 全部 执行完毕后再能执行

js中的微任务和宏任务_第1张图片

宏任务和微任务的根本区别

  • 宏任务:DOM渲染后触发,如setTimeout
  • 微任务:DOM渲染前触发,如Promise

JS代码执行的顺序:

  1. 首先执行同步代码;
  2. 同步代码执行结束后,call stack被清空,开启envet loop;
  3. 执行微任务;
  4. 触发DOM元素渲染;
  5. 触发enevt loop;
  6. 执行宏任务。

看一个例子

async function async1(){
    console.log('async1 start')   // 顺序2
    await async2()
    console.log('async1 end')    // 顺序6
}

async function async2(){
    console.log('async2')      // 顺序3
}

console.log('script start')     // 顺序1

setTimeout(function(){
    console.log('setTimeout')   // 顺序8
}, 0)

async1()

// 初始化 promise 时,传入的函数会立刻被执行
new Promise(function(resolve){
    console.log('promise1')        // 顺序4
    resolve()
}).then(function(){
    console.log('promise2')    // 顺序7
})

console.log('script end')    // 顺序5

再看一个例子

setTimeout(()=>{
    console.log("1")
    Promise.resolve().then(()=>{
        console.log("2")
    })
})
console.log("3")
Promise.resolve().then(()=>{
    console.log("4")
    setTimeout(()=>{
        console.log("5")
    })
})

分析一下上面的代码

第一个执行的是setTimeout,setTimeOut是一个宏任务,所以会先放到宏任务队列(注意:现在还不会执行,因为js脚本代码还没有执行完)
第二个执行的是console.log(“3”) //此时会直接输出3
第三个执行的是promise.resolve(),此时的then是一个微任务,所以会放到微任务队列(此时也不会执行)

js脚本代码代码执行完毕后就会先执行微任务队列中的任务

第四个执行的是微任务队列中的console.log(“4”)//此时会直接输出4
但此函数还没有执行完,后面还接了一个定时器函数,又因为此函数是一个宏任务,所以也会放到宏任务队列中去(此任务排在第二个执行)

此时微任务队列已经没有任务了,则会开始执行宏任务队列

首先执行的就是上面的setTimeout(),会直接输出 1
后面接了一个promise.then,这个函数就被放到了微任务队列中,因为微任务队列中有任务了就会先执行微任务队列,那么就会输出2

最后执行宏任务队列的定时器,则输出 5

因此最后输出的结果为 3 4 1 2 5

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