首先我们要了解和区分宏任务和微任务
异步任务
不是马上执行,是放入到队列中等待;
如果所有的任务都要按序等待,那么也不行,需要有一个能插队的机制。所以又将异步任务分为微任务和宏任务,同时对应微任务队列和宏任务队列。
微任务代码(js语法)
- Promise对象.then()
宏任务代码(宿主环境)
- script
- dom事件
- ajax
- setTimout
微任务和宏任务以及同步代码在浏览器执行时先执行第一个宏任务(<script>), 然后同步任务, 然后微任务, 然后下一个宏任务如此循环, 直到所有代码执行完毕
面试题演示 :
//先执行第一个script标签 加入宏任务(1)队列
<script>
//先执行第一个宏任务队列内的代码
//1.先输出1
console.log(1);
//注意async-await
async function fnOne() {
//2.输出2
console.log(2);
// 执行完await 然后跳出async 不再执行await下面的代码(将await下面的代码添加进微任务队列)
await fnTwo();
//7.执行第一个微任务 输出3
console.log(3);
}
async function fnTwo() {
//3.输出4
console.log(4);
}
//同步任务 函数被调用
fnOne();
//加入宏任务(5)队列(两秒后触发) 暂不执行
setTimeout(() => {
//15.执行最后一个宏任务 输出5
console.log(5);
}, 2000);
let p = new Promise((resolve, reject) => { // new Promise()里的函数体会马上执行所有代码
//4.输出6
console.log(6);
resolve();
//5.输出7
console.log(7);
})
//加入宏任务队列(3) 暂不执行
//11.执行第三个宏任务 输出8
setTimeout(() => {
console.log(8)
}, 0)
//8.第二个微任务 输出9
p.then(() => {
console.log(9);
})
//6.同步任务 输出10
console.log(10);
</script>
//第一个宏任务执行完毕 开始执行微任务
//微任务列表被清空 开始执行第二个宏任务
//第二个script标签加入宏任务(2)队列
<script>
//9.同步任务 输出11
console.log(11);
//加入宏任务队列(4) 暂不执行
setTimeout(() => {
//12.执行第四个宏任务 输出12
console.log(12);
let p = new Promise((resolve) => {// new Promise()里的函数体会马上执行所有代码
resolve(13);
})
//加入微任务队列
//第四个宏任务执行结束 开始执行微任务队列中的任务
p.then(res => {
//14.输出13
console.log(res);
})
//13.输出15
console.log(15);
}, 0)
//10.同步任务 输出14
console.log(14);
</script>
//第二个宏任务执行完毕 且微任务队列无任务 开始执行第三个宏任务 以此类推
// 按照以上执行顺序输出结果为 1 2 4 6 7 10 3 9 11 14 8 12 15 13 5