JS事件循环机制

154 阅读3分钟

来源于(JavaScript事件循环机制(event loop) - 掘金 (juejin.cn))

前提

在了解JS事件循环机制之前,先了解两点,JS是一个单线程语言JS的事件分类

JS是一个单线程语言

单线程就是JS的所有任务都在一条线程上执行处理。类似于食堂打饭,只有一个窗口,大家都在排一个队。

单线程存在一个弊端,当某个任务卡住的时候,后面的其他任务就没法执行。或者某个任务耗时很长那么就会导致后面所有的任务都被延迟执行。

在这样的环境下,JS诞生了两个任务种类:同步任务异步任务

JS的事件分类

JS中的所有任务被分为同步任务异步任务两大类。

同步任务

就是只要被扫描到,就可以被主线程马上执行的任务。(优先于所有异步任务)

类似于console.log(1)等语句。

异步任务

即使被扫描到,也不会马上执行,异步任务会被压入异步任务队列中,等待主线程中的任务全部清空了,再被召唤执行。

常见的异步任务有如下几种

  1. Promise.then() --- 微任务
  2. async/await --- 微任务
  3. setTimeout() --- 宏任务
  4. setInterval() --- 宏任务
  5. ...(还有更多,不常见的)

举个🌰

setTimeout(() => {
    console.log("1"); //同步任务
},0)   //异步任务
console.log(2)  //同步任务

以上的输出结果是 2 1

虽然setTimeout的延迟是0,但setTimeout是一个异步任务,它一定会在所有同步任务执行完毕之后再去执行。(对应前面同步代码优先于异步任务)

宏任务和微任务

JS的异步任务又被分为宏任务微任务

异步任务中:

有些异步任务的平均执行周期很长,这些任务被JS标记为宏任务(比如setTimeout())。

有些异步任务的平均执行周期短的任务,被JS标记为微任务(比如promise.then())。

宏任务微任务在执行顺序上是不一样的。具体执行机制如下:

当有异步任务被压入异步任务队列时候,JS会将这些异步任务分为宏任务微任务两个新的队列。然后,在所有同步任务执行完毕之后,异步任务会优先执行所有已经存在任务队列中的微任务。在所有的微任务执行完毕之后,再去宏任务队列中执行一个(注意是一个)宏任务,执行完一个宏任务之后会再去微任务队列中检查是否有新的微任务,有则全部执行,再回到宏任务队列执行一个宏任务,以此循环。这一套流程,就是事件循环(event loop)

image.png

例题

例题一

       setTimeout(() => {
           console.log("1") 
       }, 0);  //异步任务 - 宏任务

       console.log(2);   //同步任务

        Promise.resolve().then(() => {
            console.log(3) 
        }) //异步任务 - 微任务

        console.log(6);   //同步任务

输出结果:2 6 3 1

例题二


        //第一个宏任务
         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