原理图
异步执行的回调函数有一个共同特点:在合适的时机都会被放到队列里面去。下面来看一些哪些种类的回调函数是放到宏队列,哪些是放到微队列的
宏队列中每一个回调称为宏任务,微队列中的每一个回调称为微任务
-
宏队列:用来保存待执行的宏任务(回调)
- dom事件回调
- ajax回调
- 定时器回调
-
微队列:用来保存待执行的微任务(回调)
- promise回调
- mutation回调
setTimeout(() => {
// 会立即放入宏队列
console.log("timeout callback");
}, 0);
Promise.resolve(1).then(
value => {
// 会立即放入微队列
console.log('Promise onResolved()', value);
}
)
可以看到是下面的promise先执行,settimeout后执行的
多加一个呢??
setTimeout(() => {
// 会立即放入宏队列
console.log("timeout callback 1");
}, 0);
setTimeout(() => {
// 会立即放入宏队列
console.log("timeout callback 2");
}, 0);
Promise.resolve(1).then(
value => {
// 会立即放入微队列
console.log('Promise onResolved1()', value);
}
)
Promise.resolve(2).then(
value => {
// 会立即放入微队列
console.log('Promise onResolved2()', value);
}
)
可以看到还是promise先执行,settimeout后执行的
JS引擎是单线程执行的,单线程执行就是在某个时间点只能干一件事。也就是说它的基本整体流程分为两步:
- 先执行完所有的同步代码
- 再执行队列里面的回调函数
那还有种可能性是:初始化的同步代码还没有执行完,队列里面就有回调函数了。但是队列里面的回调函数不会执行,因为只有一条线路(只有将所有的同步代码执行完之后才能执行队列里面的回调函数)
执行队列里面的回调函数时,先执行微队列后执行宏队列
JS执行时会区分这两个队列:
- JS引擎首先必须先执行所有的初始化同步代码
- 每次准备取出第一个宏任务执行前,都要将所有的微任务一个一个取出来执行
怎么理解上面这句话呢?代码来看
setTimeout(() => {
// 会立即放入宏队列
console.log("timeout callback 1");
Promise.resolve(3).then(
value => {
// 会立即放入微队列
console.log('Promise onResolved3()', value);
}
)
}, 0);
setTimeout(() => {
// 会立即放入宏队列
console.log("timeout callback 2");
}, 0);
Promise.resolve(1).then(
value => {
// 会立即放入微队列
console.log('Promise onResolved1()', value);
}
)
Promise.resolve(2).then(
value => {
// 会立即放入微队列
console.log('Promise onResolved2()', value);
}
)
说明:
可以看到先执行了Promise onResolved1()
和 Promise onResolved2()
这两个微任务,然后去执行宏任务timeout callback 1
,这时发现宏任务中包含一个微任务Promise onResolved3()
,所以先执行了这个微任务Promise onResolved3()
之后,再去执行下一个宏任务timeout callback 2