前言

  最近在准备春招,刷到了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
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 ]
]
]

 

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

 

setTimeout(() => {
    console.log('timeout');  
   Promise.resolve().then(() => {
        console.log('p1')    //将这个回调函数叫做callback4
    }); 
});

/*
    打印结果:start 
       end
       end2
       p2
       p3
       timeout
           p1
*/

callback4 ]

]

]

至此,执行完毕。

尾声

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