本文原创:liuwanhtml
在说微任务与宏任务以前咱们先说一下同步任务与异步任务的概念吧。bash
JavaScript语言的一大特色就是单线程,也就是说,同一个时间只能作一件事。单线程就意味着,全部任务须要排队,前一个任务结束,才会执行后一个任务。若是前一个任务耗时很长,后一个任务就不得不一直等着。网络
若是排队是由于计算量大,CPU忙不过来,倒也算了,可是不少时候CPU是闲着的,由于IO设备(输入输出设备)很慢(好比Ajax操做从网络读取数据),不得不等着结果出来,再往下执行。异步
JavaScript语言的设计者意识到,这时主线程彻底能够无论IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回告终果,再回过头,把挂起的任务继续执行下去。async
因而,全部任务能够分红两种,一种是同步任务(synchronous),另外一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务能够执行了,该任务才会进入主线程执行。 具体来讲,异步执行的运行机制以下。(同步执行也是如此,由于它能够被视为没有异步任务的异步执行。)函数
以上摘自廖雪峰的博客 JavaScript 运行机制详解:再谈Event Loop.oop
咱们先看一下下面的代码,而后思考一下输出的前后顺序post
setTimeout(() =>{
console.log('1')
});
new Promise((resolve) => {
console.log('2');
resolve();
}).then(() => {
console.log('3')
});
console.log('4');
复制代码
按照同步与异步的概念来看,输出顺序应该是二、四、一、3. 可是,打开控制台,输入代码,查看输出,顺序是这样的二、四、三、1,发生了什么? ui
除了广义的同步任务和异步任务,咱们对任务有更精细的定义,分为宏任务和微任务。spa
注:Promise当即执行,then函数分发到“microtask”队列,process.nextTick分发到“microtask”队列 js引擎会把宏任务和微任务放置两个“任务队列”中,分别是“macrotask”队列以及“microtask”队列。在执行异步任务时,先执行宏任务,而后在执行微任务。
因此如今解释一下上面问题中的输出顺序问题:
因此上述问题的输出顺序知道怎么肥死了吧? 盗一张事件循环,宏任务,微任务的关系图,以下:
复习一下上面的知识点,咱们瞅一眼如下代码:
console.log('1');
setTimeout(() => {
console.log('2');
process.nextTick(() => {
console.log('3');
})
setTimeout(() => {
console.log('10')
new Promise((resolve) => {
console.log('11');
resolve();
}).then(() => {
console.log('12')
})
})
new Promise((resolve) => {
console.log('4');
resolve();
}).then(() => {
console.log('5')
})
})
process.nextTick(() => {
console.log('6');
})
new Promise((resolve) => {
console.log('7');
resolve();
}).then(() => {
console.log('8')
setTimeout(() => {
console.log('9')
})
})
console.log('10')
复制代码
大声说出答案吧:一、七、十、六、八、二、四、三、五、九、十、十一、12 好吧,咱们分析一下:
fn1
,放置“macrotask”队列中,接着执行下面的代码fn2
放置“microtask”队列fn3
会被放置“microtask”队列fn2
以及fn3
),队列具体先进先出的特色,因此先执行fn2
,输出6,而后执行fn3
,输出8,里面包含setTimeout,把它的回调函数fn4
放置“macrotask”队列中。fn1
、fn4
fn1
。fn1
,遇到console.log('2'),就输出,遇到process.nextTick,将其回调函数fn5
放置“microtask”队列,遇到setTimeout,把它的回掉函数fn6
放置“macrotask”队列中,遇到Promise,new Promise会当即执行,因而输出4,其then函数fn7
会被放置“microtask”队列,即这个宏任务执行完成。“macrotask”队列里面有fn4
、fn6
。fn5
、fn7
,把里面的任务所有执行完毕, 先执行fn5
,输出3,再执行fn7
,输出5fn4
、fn6
,执行fn4
,输出9.fn6
fn6
,输出10,遇到new Promise,输出11,并把其回调函数fn8
放置“microtask”队列,至此宏任务fn6
结束,fn8
,输出12,至此,“macrotask”队列以及“microtask”队列所有空了。