浅谈JS中事件循环的宏任务和微任务

122 阅读2分钟

javascript是一门单线程语言,也就是说代码只能一个接一个地被顺序处理,同一个时间只能做一件事。如果做某一件事时间太长,后面的执行就需要等待,需要等前面的事件执行完成,才可以往后执行。

所以为了解决这个问题,js就委托宿主浏览器去帮忙执行耗时的任务,执行完成后,再通知js去执行回调函数,而宿主环境帮我们去执行的这些耗时任务就是异步任务。 js 本身是无法发起异步的,但是 es5 之后提出了 Promise 可以进行异步操作

异步.c9bde001.png js执行的流程

  1. 主线程先判断任务类型

    • 如果是同步任务,主线程自己执行
    • 如果是异步任务,交给宿主环境(浏览器)执行
  2. 浏览器进行异步任务的执行,每个异步执行完后,会将回调放进任务队列,先执行完成的先放进任务队列,依次放入。

  3. 等主线程任务全部执行完后,发现主线程没有任务可执行了,会取任务队列中的任务,由于任务队列里是依次放入进来的,所以取得时候也会先取先进来的,也就是先进先出原则

  4. 在任务队列中取出来的任务执行完后,在取下一个,依次重复,这个过程也称为 eventLoop 事件循环

简单了解一下异步任务

异步任务又分为宏任务和微任务

宏任务一般是:包括整体代码script,setTimeoutsetInterval、setImmediate。你会发现所有宏任务都属于Web API接口下的,都是浏览器提供,有宿主发起的一个异步任务,这不是js提供的
微任务:原生Promise(Promise.then里面的回调才是一个微任务、process.nextTickMutationObserver 。这是JAvaScript标准的内置对象,由js自身发起的异步。

宏任务微任务.webp

异步任务的执行顺序

  1. 先执行宏任务
  2. 宏任务执行完后看微任务队列是否有微任务
  3. 没有微任务执行下一个宏任务
  4. 有微任务将所有微任务执行
  5. 执行完微任务,执行下一个宏任务

看一个简单的练习

      setTimeout(() => {
            console.log(2);
            new Promise((resolve) => {
                console.log(3);
                resolve()
            }).then(() => {
                console.log(4)
            })
        })

        new Promise((resolve) => {
            console.log(5);
            resolve()
        }).then(() => {
            console.log(6)
        })

        setTimeout(() => {
            console.log(7)
        })

结果为5、6、2、3、4、7,

遇到宏任务中有微任务的话,先把这个宏任务中的微任务执行完,也就是要把微任务清空,才会去执行下一个微任务