Eventloop,微任务和宏任务

1. Eventloop 事件循环机制

1.1 概述

Javascript 中先分【同步和异步】,然后事件任务分为【宏任务和微任务】, 执行顺序是先执行微任务再执行宏任务。(异步顺序也是如此)

先执行主线程同步的微任务,发现异步之后,放入到异步队列中

然后执行同步的宏任务,宏任务执行完毕

执行刚才的异步任务。此顺序反复执行loop

宏任务:整体代码 script,setTimeout,setInterval

微任务:Promise.then(非new Promise)

1.2 执行栈和队列

(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。

(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。

(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。

(4)主线程不断重复上面的第三步。

2. 宏任务和微任务

2.1 概述

(1)宏任务:当前调用栈中执行的代码成为宏任务。(主代码块,定时器等等)。

(2)微任务:当前(此次事件循环中)宏任务执行完,在下一个宏任务开始之前需要执行的任务,可以理解为回调事件。(promise.then,proness.nextTick等等)。

(3)宏任务中的事件放在 callback queue中,由事件触发线程维护;微任务的事件放在微任务队列中,由 js引擎线程维护。

2.2 执行顺序

两个任务皆为 异步任务,区别就是执行顺序。消息队列 有微先走微,微可插宏队

macrotasks(宏任务): setTimeoutsetInterval,setImmediate,I/O,UI rendering

microtasks(微任务): process.nextTick(node环境),Promise,MutationObserver

3. 例题

Promise.resolve().then( () => {            
  console.log('Promise1');                // 1
  setTimeout( () => {                    
    console.log('setTimeout2');            // 4
  }, 0)
});
setTimeout( () => {                        // 异步宏任务
  console.log('setTimeout1');            // 2
  Promise.resolve().then( () => {
    console.log('Promise2');            // 3
  })
}, 0)
// Promise1,setTimeout1,Promise2,setTimeout2

题目解析:

(1)先走主线程,promise 直接 resolve,then 里面函数属于异步微任务, setTimeout1 属于异步宏任务,0延迟后,都放入事件环。

(2)当主线程走完,将事件环内的函数放入主线程,先微后宏,打印 Promise1,然后再次遇 setTimeout,放入事件环。

(3)setTimeout1 回调执行, 打印 setTimeout1,遇到 promise 放入事件环,主线程第二遍走完,现在事件环有 setTimeout2 和 Promise2。

(4)微任务可插队宏任务,先打印 Promise2,再打印 setTimeout2