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(宏任务): setTimeout,setInterval,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