javascript宏任务与微任务

同步任务和异步任务

javascript是单线程。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。

所有的任务分为两种,一种是同步任务,一种是异步任务。

同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;

异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。

我们可以通过代码来感受一下。

console.log(1);
    setTimeout(function() {
        console.log(2);
    });
    console.log(3);

在这里插入图片描述
由此我们可以看到,console.log属于同步任务,setTimeout属于异步任务。

javascript执行代码的顺序为从上到下一次执行,如果setTimeout是同步任务就应该是输出123,既然输出的是132也就是说,setTimeout里的函数并没有立即执行,而是延迟了一段时间,满足一定条件后,才去执行的,这类代码,我们叫异步代码。

宏任务和微任务

首先我们要明确一点,宏任务和微任务都在任务队列。

宿主发起的任务为宏观任务,如setTimeout、setInterval。

为了更好地理解,我们可以将其比喻为到银行办理业务的用户,由于业务员一次只能办理一个用户的业务,每一个用户都可以看作是一个宏任务。

微任务仅来自于我们的代码。它们通常是由 promise 创建的,微任务也被用于 await 的“幕后”,因为它是 promise 处理的另一种形式。

对于微任务的理解我们依然可以使用银行办理业务来比喻,对于正在办理业务的人,在当前业务办理完成后,可能还会有其他业务要办,那么这个后来添加的任务就是微任务。

那么下一个宏任务就会往后延迟,在当前宏任务的微任务没有全部完成时是不会执行下一个宏任务的。

也就是说,每个宏任务之后,引擎会立即执行微任务队列中的所有任务,然后再执行其他的宏任务,或渲染,或进行其他任何操作。
微任务会在执行任何其他事件处理,或渲染,或执行任何其他宏任务之前完成。

为什么有了宏任务,还会有微任务存在?因为宏任务太占用性能,当需要一些较早就准备好的方法,排在最后才执行的时候,又不想新增一个宏任务,那么就可以把这些方法,一个一个的放在微任务队列里面,在这个宏任务中的代码执行完后,就会执行微任务队列。

那么,我们也可以利用代码更好地理解宏任务和微任务。

setTimeout(() => console.log(4))

new Promise(resolve => {
  resolve()
  console.log(1)
}).then(_ => {
  console.log(3)
})

console.log(2)

效果如下
javascript宏任务与微任务_第1张图片
我们可以根据输出结果来判断哪些是宏任务,哪些是微任务。

但是根据结果我们可以看出,首先输出的是1,而不是2,这也就说明new Promise不是异步任务,是同步任务,resolve和then才是异步的。

也就是说当前代码中只有then和setTimeout才是异步的,在同步代码执行完成后才回去检查是否有异步任务完成,并执行对应的回调,而微任务又会在下一个宏任务之前执行,因此输出1,2,3,4。

事件循环

事件循环 是一个在 JavaScript 引擎等待任务,执行任务和进入休眠状态等待更多任务这几个状态之间转换的无限循环。
引擎的一般算法:
当有任务时:

  • 从最先进入的任务开始执行。
  • 休眠直到出现任务,然后转到第 1 步。
    当我们浏览一个网页时就是上述这种形式。JavaScript 引擎大多数时候不执行任何操作,它仅在脚本/处理程序/事件激活时执行。
    一个任务到来时,引擎可能正处于繁忙状态,那么这个任务就会被排入队列。多个任务组成了一个队列,即所谓的“宏任务队列”。宏任务的队列可以理解为一个事件循环。
    javascript宏任务与微任务_第2张图片

执行任务的顺序

  1. 从 宏任务 队列(例如 “script”)中出队(dequeue)并执行最早的任务。
  2. 执行所有 微任务:
    当微任务队列非空时:
    出队(dequeue)并执行最早的微任务。
  3. 如果有渲染任务,执行渲染。
  4. 如果宏任务队列为空,则休眠直到出现宏任务。
  5. 转到步骤 1。

你可能感兴趣的:(JavaScript,javascript,队列,前端,ecmascript)