宏任务与微任务

宏任务与微任务

之前写过关于事件循环机制的文章 js 的并发模型一文,当时以为已经讲清楚所有这方面的概念了,但是最近又发现,事件循环机制还有宏任务与微任务这个概念没有涉及,所以这里延续之前的文章,再继续讲一讲。

概念

在之前的博客里已经讲清楚了事件循环机制是如何运行的(js 的并发模型 地址)。

当时是这么理解的,当执行引擎在主线程方法执行完毕,到达空闲状态时,会从任务队列中按顺序获取任务来执行(task-> task-> task…)

这里补充一个概念,浏览器为了能够使得 JS 内部 task(任务) 与 DOM 任务能够有序的执行,会在一个 task 执行结束后,在下一个 task 执行开始前,对页面进行重新渲染 (task-> 渲染-> task->…)

宏任务(task):就是上述的 JS 内部(任务队列里)的任务,严格按照时间顺序压栈和执行。如 setTimeOut、setInverter、setImmediate 、 MessageChannel等

微任务(Microtask ):通常来说就是需要在当前 task 执行结束后立即执行的任务,例如需要对一系列的任务做出回应,或者是需要异步的执行任务而又不需要分配一个新的 task,这样便可以减小一点性能的开销。microtask 队列是一个与 task 队列相互独立的队列,microtask 将会在每一个 task 执行结束之后执行。每一个 task 中产生的 microtask 都将会添加到 microtask 队列中,将会添加至当前 microtask 队列的尾部,并且 microtask 会按序的处理完队列中的所有任务,然后开始执行下一个 task 。microtask 类型的任务目前包括了 MutationObserver 以及 Promise 的回调函数。

或许看完还是一脸懵逼,所以还是得分析例子

例子

例子1:

console.log("script start");
Promise.resolve().then(function(){
	console.log("promise1")
})
setTimeout(function(){
    console.log("setTimeout")
},0);
Promise.resolve().then(function(){
	console.log("promise2")
})
console.log("script end");

//输出
//script start
//script end
//promise1
//promise2
//setTimeout

在这里插入图片描述

(1)当前 JS 代码进入主线程被 JS 引擎执行,当前是一个宏任务。按序执行,先输出script start

(2) 接着执行 Promise.resolve(1),该回调进入微任务

(3)执行 setTimeout,回调进入宏任务(这个宏任务是下一个宏任务,而不是当前宏任务)

(4)执行Promise.resolve(2),该回调进入微任务

(5)继续执行,输出script end,当前宏任务执行完毕。检测微任务列表

(6)执行微任务列表,按顺序输出 promise1 promise2

(7)当前微任务列表为空,渲染 DOM 后执行下一宏任务,即 setTimeout 回调函数,输出 setTimeout

例子2:

console.log('script start');
Promise.resolve().then(function() {
  	setTimeout(function() {
      console.log('setTimeout1');
    }, 0);
}).then(function() {
  console.log('promise1');
});

setTimeout(function() {
	console.log('setTimeout2')
	Promise.resolve().then(function(){
		console.log('promise2');
	})
},0)
console.log('script end');

//输出:
//script start
//script end
//promise1
//setTimeout2
//promise2
//setTimeout1

在这里插入图片描述

(1)进入宏任务,执行当前代码,输出 script start

(2)执行 Promise.resolve(1),回调(内含函数 setTimeout(1))进入微任务

(3)执行 setTimeout(2),回调(内含函数 Promise.resolve(2)) 进入下一宏任务

(4)输出 script end,当前宏任务结束。

(5)宏任务结束,查看微任务队列,当前微任务是 Promise.resolve(1) 回调,执行回调里面的 setTimeout(1),定时器回调进入宏任务,接着输出 promise1,当前微任务为空

(6)当前微任务为空,执行下一宏任务。当前宏任务是 setTimeout(2)回调,输出 setTimeout2,执行回调里面的 Promise.resolve(2),回调进入微任务,当前宏任务结束

(7)当前宏任务结束,执行微任务。输出 Promise2,微任务为空。

(8)执行下一宏任务,setTimeout1 回调输出 setTimeout1

可以画图帮助理解,弄清楚上面这个流程基本上就理解这个知识了

当然有时候有些浏览器并不是这么表现,例如会把 Promise.resolve 当成当成宏任务处理,但是都是特殊情况,因为这样消耗会变很大,如上面流程显示才是最标准的。

最后结合上并发模型博客里讲的定时器线程再来一个例子仅供玩耍

console.log('script start');
Promise.resolve().then(function() {
  	setTimeout(function() {
      console.log('setTimeout1');
    }, 0);
}).then(function() {
  console.log('promise1');
});

setTimeout(function() {
	console.log('setTimeout2')
	Promise.resolve().then(function(){
		console.log('promise2');
	})
},3000)
console.log('script end');

//输出:
//script start
//script end
//promise1
//setTimeout1
//setTimeout2
//promise2
  • 12
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值