• 如何理解EventLoop--浏览器篇


    前言

      最近在准备春招,刷到了JS中的主要运行机制--Event Loop,觉得它的实现思路有必要整理一下,以防忘记。关于它在浏览器上的实现,我结合了自己的理解以及示例代码,想用最通俗的语言表达出来。如果在文中出现书写错误的地方,欢迎大家留言一起探讨。

    正文

      关于Event Loop,宏任务,微任务的概念不再此赘述了。

    概念

      进入主题,我理解的浏览器的事件循环Event Loop,以及执行一个JavaScript代码的流程如下:

    1. 一开始整段脚本作为第一个宏任务执行;
    2. 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列;
    3. 当前宏任务执行完出队,检查微任务队列,如果有则依次执行,直到微任务队列为空;如果在执行微任务的过程中,又产生了微任务,那么会加入到队列的末尾,也会在这个周期被调用执行;
    4. 执行浏览器 UI 线程的渲染工作;
    5. 执行队首新的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空。

    代码

     1     console.log('start');
     2     
     3     setTimeout(() => {
     4       console.log('timeout');
     5       Promise.resolve().then(() => {
     6         console.log('p1')
     7       });
     8     });
     9 
    10     Promise.resolve().then(() => {
    11       console.log('p2');
    12     });
    13 
    14     console.log('end');
    15 
    16     new Promise((resolve, reject) => {
    17       console.log('end2')
    18       resolve('p3')
    19     }).then((data) => {
    20       console.log(data);
    21     })    
    //输出结果为:
        start 
        end
        end2
        p2
        p3
        timeout
        p1

    解析:

    Step 1:执行全局Script代码

    console.log('start');
    //打印结果:start

      栈:[ console ]

      宏任务队列:[ ]

      微任务队列:[ ]

    setTimeout(() => {
        console.log('timeout');//将这个回调函数叫做callback1,由于setTimeout属于宏任务,所以放到宏任务队列
       Promise.resolve().then(() => {
            console.log('p1')
        }); 
    });
    
    //打印结果:start

      栈:[ setTimeout ]

      宏任务队列:[ callback1 ]

      微任务队列:[ ]

    Promise.resolve().then(() => {
       console.log('p2');  //将这个回调函数叫做callback2,由于Promise属于微任务,所以放到微任务队列
     });
    
    //打印结果:start 

      栈:[ Promise ]

      宏任务队列:[ callback1 ]

      微任务队列:[ callback2 ]

    console.log('end');
    
    /*
        打印结果:start 
             end
    */

      栈:[ console ]

      宏任务队列:[ callback1 ]

      微任务队列:[ callback2 ]

     new Promise((resolve, reject) => {
          console.log('end2')  //注意,这里是同步执行的!!!
          resolve('p3')  //将这个回调函数叫做callback3,由于Promise属于微任务,所以放到微任务队列
        }).then((data) => {
          console.log(data);
        })
    
    /*
        打印结果:  start 
             end
             end2
    */

      栈:[ Promise ]

      宏任务队列:[ callback1 ]

      微任务队列:[ callback2 callback3 ]

    Step 2:全局Script代码执行完成,进入微任务队列,取出任务并执行,直至微任务队列为空。

      微任务队列:[ callback2 callback3 ]

      1.首先执行callback2任务:

    Promise.resolve().then(() => {
       console.log('p2');  //将这个回调函数叫做callback2
     });
    
    //打印结果:start 
          end
          end2
          p2

      栈:[ callback2 ]

      宏任务队列:[ callback1 ]

      微任务队列:[ callback3 ] 

      2.其次执行callback3任务:

     new Promise((resolve, reject) => {
          console.log('end2')  //注意,这里是同步执行的
          resolve('p3')  //将这个回调函数叫做callback3
        }).then((data) => {
          console.log(data);
        })
    
    /*
        打印结果:start 
           end
           end2
           p2
           p3
    */

      栈:[ callback3 ]

      宏任务队列:[ callback1 ]

      微任务队列:[ ] 

    Step3:微任务队列全部执行完,再去宏任务队列中取第一个任务执行。

    setTimeout(() => {
        console.log('timeout');  //将这个回调函数叫做callback1
       Promise.resolve().then(() => {
            console.log('p1')    //将这个回调函数叫做callback4
        }); 
    });
    //打印结果:start 
           end
           end2
           p2
           p3

           timeout

    【注】:当执行callback1的时候又遇到了另一个promise,promise异步执行完后在微任务队列中又注册了一个callback4回调函数。

      栈:[ callback1 ]

      宏任务队列:[ ]

      微任务队列:[ callback4 ] 

    Step4:当前宏任务执行完出队,检查微任务队列

    setTimeout(() => {
        console.log('timeout');  
       Promise.resolve().then(() => {
            console.log('p1')    //将这个回调函数叫做callback4
        }); 
    });
    
    /*
        打印结果:start 
           end
           end2
           p2
           p3
           timeout
               p1
    */ 

      栈:[ callback4 ]

      宏任务队列:[ ]

      微任务队列:[ ]

    至此,执行完毕。

    尾声

    以上就是我分析的浏览器篇Event Loop的一个例子,如有错误,还请指正,谢谢!希望本次分享对你有用呀 ^_^

  • 相关阅读:
    CleanWebpackPlugin
    webpack
    kubeadm部署k8s
    leetcode 148 链表排序的归并排序和插入排序
    102 二叉树层序遍历(一下出一层的广搜和DFS)
    139 单词拆分 dp
    48 旋转图像 水平翻转然后主对角线翻转即可实现顺时针旋转90°
    31下一个排列
    最长连续序列
    每日总结22——SQL语句(保持现有内容在后面增加内容)
  • 原文地址:https://www.cnblogs.com/zx0423/p/12641637.html
Copyright © 2020-2023  润新知