CSDN事件循环、消息队列
阮一峰事件循环、消息队列
简书事件循环,宏任务,微任务
如果完全不懂消息队列、事件循环、以及微任务宏任务的同学建议看了上面三片博客再来看下面的内容:
这三篇博客,还有博客中的链接都值得看一下,讲解得比较详细了,但是有些表达得不准确的地方和讲得不完整的地方,所以我这里再做一些总结和补充:
消息队列可分为宏任务消息队列和微任务消息队列。宏任务消息队列只有一个,微任务消息队列是依附在每个宏任务消息下的(宏任务下有自己的微任务,微任务属于自己的宏任务),也就是说微任务消息队列可以有很多个,但是同时只会存在一个,这是由于在一个宏任务执行完后,才会继续执行下一个宏任务,而一个宏任务执行完毕也意味着这个宏任务下的微任务消息队列中的所有微任务都被执行完毕了。
另外:
微任务下创建的宏任务,会被继续添加到那个唯一的宏任务消息队列中,照常进行着宏任务的事件循环。
宏任务下创建的宏任务,跟微任务下创建的宏任务是一样的,也会被添加到那个唯一的宏任务消息队列中。
以上两点表明,宏任务就是宏任务,不管在哪里被触发创建它都是宏任务,它不是任何任务的子任务,它只会被添加到那一个唯一的宏任务消息队列中,只是被触发创建的地方不一样。
微任务下创建的微任务就不太一样了,微任务是有附属性质的,父微任务下的子微任务就是父微任务的一部分,不管一个微任务下嵌套多少的子微任务、孙微任务,一个微任务执行完意味着它下面的所有后代微任务都在执行完。其次,一个宏任务下的不同的没有父子关系的微任务,按照不同的层级顺序先后调用,比如:。
var p2 = new Promise(function (resolve, reject) {
resolve(1);
});
p2.then(function (value) {//(这个微任务第一个调用)
console.log(value); // 1
return value + 1;
}).then(function (value) {//(这个微任务第三个调用)
console.log(value + ' - A synchronous value works'); // 2 - A synchronous value works
});
p2.then(function (value) {//(这个微任务第二个调用)
console.log(value); // 1
});
这种层级顺序就是完全按照是写的第几层来的,即使那一层没有调用,比如说:
const p1 = new Promise((res, rej) => {
res(1);
});
const p2 = new Promise((res, rej) => {
rej(2);
});
p1.then(v => { //第一个被调用
console.log(v);
return ('' + v + v);
}).then(v => { //第二个被调用(实际上的微任务队列里面是第三个)
console.log(v);
});
p2.then(v => { //这一层虽然不会被调用,还是算一层(实际上的微任务队列里面是第二个)
}).catch(e => {//第三个被调用(实际上的微任务队列里面是第四个)
console.log(e);
return ('' + e + e);
}).then(v => {//第四个被调用(实际上的微任务队列里面是第五个)
console.log('完啦');
});
如果把p2的第一个then去掉,调用顺讯就会发生变化:
const p1 = new Promise((res, rej) => {
res(1);
});
const p2 = new Promise((res, rej) => {
rej(2);
});
p1.then(v => { //第一个被调用
console.log(v);
return ('' + v + v);
}).then(v => { //第三个被调用(实际上的微任务队列里面是第三个)
console.log(v);
});
// 去掉第一个then
p2.catch(e => {//第二个被调用(实际上的微任务队列里面是第二个)
console.log(e);
return ('' + e + e);
}).then(v => {//第四个被调用(实际上的微任务队列里面是第四个)
console.log('完啦');
});
上面这两个规律也不是绝对正确的,应该还和每个then的执行时间有关
所以现在再回想一下宏任务执行完的标准,是否有更深的理解了呢。