js 运行机制 – 异步任务的执行顺序
js 是单线程执行的,会把任务分为同步和异步,这两者的执行环境不同,同步任务会进入主线程,异步任务会进入事件队列(EventQueue),当主线程代码执行完毕后,会去事件队列中读取对应的异步任务,并推到主线程中执行,不断重复过程,称为事件循环机制。
同步任务:只要被系统扫描到,就会被主线程马上执行的任务(优先于所有的异步任务)
异步任务:即使被扫描到,也不会马上执行,会被放到事件队列中,等主线程任务执行完毕,系统才会召回执行
常见的异步任务:
1、Promise.then() === 微任务
2、async/await === Promise语法糖 === 微任务
3、事件处理函数
4、setTimeout() 和 setInterval() === 宏任务
setTimeout(() => {
console.log(1)
}, 0)
console.log(2)
// 会先打印 2 然后打印 1
// 虽然setTimeout延迟为0,但它是一个异步任务,所以一定会在同步任务执行完后再去执行它
异步任务又被分为宏任务和微任务
异步任务的执行顺序
- 会优先执行已经存在于任务队列中的微任务
- 在所有的微任务执行完后,再去执行一个宏任务(只执行一个)
- 执行完宏任务,会再去微任务队列检查是否有新的微任务,有则全部执行
- 再回到宏任务队列执行一个宏任务
- 以此循环,整个流程就是事件循环机制
//第一个宏任务
setTimeout(() => {
console.log(1) //宏任务中的同步任务
Promise.resolve().then(() => {
console.log(7)
}) //宏任务中的微任务
}, 0) //异步任务 - 宏任务
console.log(2) //同步任务
Promise.resolve().then(() => {
console.log(3)
}) //异步任务 - 微任务
//第二个宏任务
setTimeout(() => {
console.log(8) //宏任务中的同步任务
setTimeout(() => {
console.log(5)
}, 0) //宏任务中的宏任务 第四个宏任务
}, 0)
//第三个宏任务
setTimeout(() => {
Promise.resolve().then(() => {
console.log(4)
}) //宏任务中的微任务
}, 0)
console.log(6) //同步任务
// 2 6 3 1 7 8 4 5
解析:
先执行同步任务 ----- 2 ,6
接下来去执行异步 异步中先执行微任务 ----- 3
接着执行异步的一个宏任务 ----- 1
再去执行异步的微任务 ----- 7
接着执行异步一个宏任务 ----- 8
下一个微任务 ----- 4
最后的一个宏任务 ----- 5