为什么任务要分为同步任务和异步任务
试想一下,如果js的任务都是同步(书写顺序和执行顺序一致)的,那么遇到定时器、网络请求等这类型需要延时执行的任务会发生什么?
页面可能会瘫痪,需要暂停下来等待这些需要很长时间才能执行完毕的代码
所以,又引入了异步任务。
- 同步任务:同步任务不需要进行等待,必须立即看到执行结果,比如console
- 异步任务:异步任务需要等待一定的时候才能看到结果,比如setTimeout、网络请求
宏任务和微任务
异步任务,又可以细分为宏任务和微任务。下面列举常用的宏任务和微任务。
| 任务(代码) | 宏/微 任务 | 环境 |
|---|---|---|
| script | 宏任务 | 浏览器 |
| 事件 | 宏任务 | 浏览器 |
| 网络请求(Ajax) | 宏任务 | 浏览器 |
| setTimeout() 定时器 | 宏任务 | 浏览器 / Node |
| fs.readFile() 读取文件 | 宏任务 | Node |
| Promise.then() | 微任务 | 浏览器 / Node |
示例
console.log('1')
new Promise((resolve, reject) => {
resolve('2')
}).then((res) => {
console.log(res)
})
setTimeout(() => {
console.log('3')
})
new Promise((resolve, reject) => {
resolve('4')
}).then((res) => {
console.log(res)
})
console.log('5')
输出结果:1,5,2,4,3
分析:
- 先执行同步代码
- 遇到宏任务,放入队列
- 遇到微任务,放入微任务队列
- 执行栈为空
- 将微任务入栈执行
- 所有的微任务完成之后,取出宏任务队列来执行
案例1
console.log(1)
setTimeout(function() {
console.log(2)
new Promise(function(resolve) {
console.log(3)
resolve()
}).then(function() {
console.log(4)
})
})
new Promise(function(resolve) {
console.log(5)
resolve()
}).then(function() {
console.log(6)
})
setTimeout(function() {
console.log(7)
new Promise(function(resolve) {
console.log(8)
resolve()
}).then(function() {
console.log(9)
})
})
console.log(10)
输出结果:1,5,10,6,2,3,4,7,8,9
思路分析
案例2
<script>
console.log(1);
async function fnOne() {
console.log(2);
await fnTwo(); // 右结合先执行右侧的代码, 然后等待
console.log(3);
}
async function fnTwo() {
console.log(4);
}
fnOne();
setTimeout(() => {
console.log(5);
}, 2000);
let p = new Promise((resolve, reject) => { // new Promise()里的函数体会马上执行所有代码
console.log(6);
resolve();
console.log(7);
})
setTimeout(() => {
console.log(8)
}, 0)
p.then(() => {
console.log(9);
})
console.log(10);
</script>
1,2,4,6,7,10,3,9,8,5
<script>
console.log(11);
setTimeout(() => {
console.log(12);
let p = new Promise((resolve) => {
resolve(13);
})
p.then(res => {
console.log(res);
})
console.log(15);
}, 0)
console.log(14);
</script>
11,14,12,15,13
案例3
使用return,翻转执行顺序
Promise.resolve()
.then(() => {
console.log(0)
// 跳出函数,不将.then加入下一次队列
return Promise.resolve(4)
}).then(res => {
console.log(res)
})
.then(() => {
console.log(7)
}).then(() => {
console.log(8)
})
Promise.resolve()
.then(() => {
console.log(1)
}).then(() => {
console.log(2)
}).then(() => {
console.log(3)
}).then(() => {
console.log(5)
}).then(() => {
console.log(6)
})
Promise.resolve()
.then(() => {
console.log(555);
}).then(() => {
console.log(666);
}).then(() => {
console.log(777);
}).then(() => {
console.log(888);
}).then(() => {
console.log(999);
})
结果:0,1,555,2,666,3,777,4,5,888,7,6,999,8
解析:
每一个.then都是一个微任务,一个.then执行完后,会将下一次.then加入到队列中。