JavaScript宏队列与微队列

305 阅读2分钟

理解宏队列与微队列能够让你看懂 js 代码的执行顺序

js代码的执行顺序是从上到下,先执行同步代码,再由宏队列与微队列决定回调函数的执行先后

  1. 会先执行所有的同步代码,
  2. 之后在宏队列中想要取出第一个宏任务执行前,会先在微队列中将所有的微任务依次取出全部执行完毕,
  3. 微队列里面的所有微任务执行完毕,才会进行下一个宏任务

宏队列

  • 存放在宏队列中执行的回调函数:
    • dom事件回调
    • ajax回调
    • 定时器回调

微队列

  • 存放在微队列中执行的回调函数:
    • promise回调
    • mutation回调
<script type="text/javascript">
    setTimeout(() => {
        console.log("0") // setTimeout的回调 添加到宏任务
    }, 0)
    
    new Promise((resolve,reject)=>{
        console.log("1") //同步调用,立即执行
        resolve() // 这里调用 resolve 之后就会立即执行.then 的回调
    }).then(()=>{
        console.log("2") // 这里是第一个回调执行,添加到微任务
        new Promise((resolve,reject)=>{
            console.log("3") // 这里是第一个微任务执行的代码,所有这里会立即执行
            resolve() // 这里调用 resolve 之后就会立即执行.then 的回调
        }).then(()=>{
            console.log("4") // 这里是第二个回调执行,添加到微任务
        }).then(()=>{ // 按照顺序执行,这个异步回调会被缓存,因为 4 还没立即执行
            console.log("5") // 这里是第四个回调执行,添加到微任务
        })
        // 在所有.then 执行后执行下一步
    }).then(()=>{
        console.log("6") // 这里是第三个回调执行,添加到微任务
    })
    
    new Promise((resolve,reject)=>{
        console.log("7") //同步调用,立即执行
        resolve()
    }).then(()=>{
        console.log("8")
    })
</script>
/*
    打印的结果: 1 7 2 3 8 4 6 5 0
    宏队列: []
    微队列: []
    根据 js 代码执行输出顺序是什么:
    第一步:先初始化执行同步代码:
    console.log("1")
    console.log("7")
    第二步:将回调区分,将宏任务添加到宏队列中, 将微任务添加到微队列中:
        第一步 setTimeout的回调 添加到宏任务 也就是宏队列:[0]
        第二步 console.log("2") Promise回调 添加到微队列:[2],但是 .then 还没结束
        第三步 console.log("8") Promise回调 添加到微队列:[2, 8],
        第四步 这时候初始化执行已经结束,这时候去取微队列的第一个微任务执行,结果:[8]
        第五步 在取出 2 这一个微任务执行,执行过程直接 同步打印出 3
        第六步 在上一步微任务执行后,又产生新的微任务(console.log("4")):[8, 4]
        第七步 4 之后 5 不会立即执行,因为 4  还没从微任务中取出执行,而 6 在前面的所有 .then之后执行回调,添加到微任务中:[8, 4, 6]
        第八步 在 6 添加到微队列后,已经没有其他任务,开始执行微队列任务:[4, 6], 再执行:[6]
        第九步 在 执行 4 这个微任务之后,就会开始执行之后的回调,将 5 添加到微任务:[6, 5]
        第十步 之后执行微队列:[]
        第十一步 微队列执行完毕,开始执行宏队列的第一个宏任务

*/