美文网首页
Javascript的事件循环

Javascript的事件循环

作者: _hider | 来源:发表于2020-06-16 17:40 被阅读0次

    javascript事件循环是执行栈,还有微任务和宏任务之间的关联,看了很多网上的文章,大多对事件循环秉持的观点如下:

    执行栈执行同步代码,宏任务和微任务执行异步代码。执行栈中同步代码执行完毕之后,再执行微任务队列,等微任务队列执行完毕后,再执行宏任务队列,然后再执行微任务对列循环往复执行。

    先不说改观点是对是错,先看宏任务和微任务既然都是执行异步代码的消息队列,两者又有什么区别:

    • 宏任务macrotaskscript(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering
    • 微任务microtaskprocess.nextTick, Promise, Object.observe(已废弃)。

    宏任务中有script(整体代码),这个就比较疑惑了?如果script(整体代码)是宏任务的话,那肯定是宏任务先执行,因为script(整体代码)在一开始就会执行。在之前的观点中明明是微任务先执行,然后再执行宏任务,这个就比较矛盾了。所以以上的观点是值得商榷的,事件循环从script(整体代码)开始第一次循环。之后全局上下文进入函数调用栈。直到调用栈清空(只剩全局),然后执行所有的微任务。当所有可执行的微任务执行完毕之后。循环再次从宏任务开始,找到其中一个任务队列执行完毕,然后再执行所有的微任务,这样一直循环下去。

    看一道经典的面试题来加深事件循环的理解:

    <script>
        let timer1 = setTimeout(() => console.log('setTimeout1'), 0);  //1宏任务
        let timer2 = setTimeout(() => { //2宏任务
            console.log('setTimeout2');
            let promise2 = Promise.resolve().then(() => { //2微任务
                console.log('promise3');
                let promise3 = Promise.resolve().then(() => { //3微任务
                    console.log('promise4');
                });
                console.log(5);
            });
            let timer4 = setTimeout(() => console.log('setTimeout4'), 0);  //4宏任务
        }, 0);
        let timer3 = setTimeout(() => console.log('setTimeout3'), 0);  //3宏任务
        console.log("console1")
        let promise1 = Promise.resolve().then(() => {  //1微任务
            console.log('promise1');
        });
    </script>
    
    1. 开始script整体代码执行宏任务。
    2. timer1,timer2,timer3是异步代码,依次进入宏任务队列等待执行。
    3. 同步代码入执行栈,输出console1
    4. 接下来是promise1,进入微任务队列并执行,输出promise1
    5. 第一轮宏任务循环结束,开始第二轮宏任务,timer1执行并输出setTimeout1
    6. 第二轮宏任务结束,开始第三轮宏任务,执行timer2,代码如下:
    let timer2 = setTimeout(() => { //2宏任务
        console.log('setTimeout2');
        let promise2 = Promise.resolve().then(() => { //2微任务
            console.log('promise3');
            let promise3 = Promise.resolve().then(() => { //3微任务
                console.log('promise4');
            });
            console.log(5);
        });
        let timer4 = setTimeout(() => console.log('setTimeout4'), 0);  //4宏任务
    }, 0);
    
    1. 同步代码入执行栈,执行并输出setTimeout2
    2. promise2进入微任务队列开始执行,执行同步代码,依次输出promise35
    3. promise3进入微任务队列开始执行,输出promise4,要注意的是当结束一轮宏任务之后,必须执行当前所有的微任务,才能进入下一轮宏任务。
    4. 然后发现该轮宏任务循环还有个timer4,排入宏任务队列。
    5. 因为队列是先进先出,timer3timer4先进入宏任务队列,所以先执行timer3,输出setTimeout3
    6. 最后执行timer4,输出setTimeout4

    相关文章

      网友评论

          本文标题:Javascript的事件循环

          本文链接:https://www.haomeiwen.com/subject/yvabtktx.html