Promise、宏任务、微任务

126 阅读2分钟

前言

  在面试和工作过程中,我们经常接触到,Promise、宏任务和微任务的顺序执行问题。首先我们要知道的,JS是一门单线程的计算机语言,原因是当我们在浏览中获取节点,如果JS是多线程,我删除了一个节点,此时,我执行了一个操作点击了这个节点,多线程的时候,这个节点已经被删除了,是点击不了的,此时就会报错。这个特性决定了JS是一门单线程的语言。

什么是宏任务

  宏任务,可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。

宏任务包括那些

script(整体代码)
setTimeout
setInterval
I/O
UI交互事件
postMessage

什么是微任务

  可以理解为在浏览器渲染之前,当前任务执行结束后立即执行的任务。

微任务包括那些

Promise.then
Object.observe
MutationObserver

微任务和宏任务的执行顺序是怎样的?

同步任务-->微任务-->DOM渲染-->宏任务

事件循环(event loop)

  是让JS做到既是单线程,又绝对不会阻塞的核心机制,也是JS并发模型的基础。是用来协调各种事件、用户交互、脚本执行、UI渲染、网络请求的一种机制。在执行和协调各种任务时,Event Loop会维护自己的事件队列。

  任务队列:在JS中,异步任务被分为两种,一种是宏任务,一种是微任务。

误区:

  1. 认为new Promise是微任务,真正的new Promise为同步任务。详情可以了解Promise规范。或者看一下Promise源码。

    setTimeout(() => { console.log('宏') }, 0)
    new Promise(() => console.log('微'));
    setTimeout(() => { console.log('宏') }, 0)
    上述代码执行的结果为: 微、宏、宏。
    
  2. 微任务不一定先于宏任务执行。

    先执行同步代码
    遇到异步宏任务则将宏任务放入宏任务队列中。
    遇到异步微任务则将微任务放入微任务队列中。
    当所有同步代码执行完毕后,在将异步微任务从队列中调入主线程执行。
    微任务执行完毕后再讲异步宏任务从队列中调入主线程执行
    一直循环直至所有任务执行完毕