前言
在面试和工作过程中,我们经常接触到,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中,异步任务被分为两种,一种是宏任务,一种是微任务。
误区:
-
认为new Promise是微任务,真正的new Promise为同步任务。详情可以了解Promise规范。或者看一下Promise源码。
setTimeout(() => { console.log('宏') }, 0) new Promise(() => console.log('微')); setTimeout(() => { console.log('宏') }, 0) 上述代码执行的结果为: 微、宏、宏。 -
微任务不一定先于宏任务执行。
先执行同步代码 遇到异步宏任务则将宏任务放入宏任务队列中。 遇到异步微任务则将微任务放入微任务队列中。 当所有同步代码执行完毕后,在将异步微任务从队列中调入主线程执行。 微任务执行完毕后再讲异步宏任务从队列中调入主线程执行 一直循环直至所有任务执行完毕