console.log(1); setTimeout(() => { console.log(2); }, 0); new Promise((resolve, reject) => { console.log(3); resolve(); }).then(data => { console.log(4); setTimeout(() => { console.log(5); }, 0); });
讲解以前先看一段代码,能够先预测一下代码的执行结果,首先打印了1,而后是一个定时器,由于js是单线程,因此代码不会等到定时器执行完在继续代码,定时器会放到异步队列里面,等到合适的时机再执行。再下面是一个promise,那么promise何时执行呢?
上面这张图片是代码执行的具体过程,console.log(1)是同步代码,直接执行,遇到定时器后,定时器是异步任务,定时器的时间到了会立刻把回调函数加入宏任务队列里面,Promise是同步任务,直接执行,promise().then是一个微任务,因此把console.log(4)放到了微任务的队列,接着里面是一个定时器,时间到了就把定时器放到了宏任务队列里面,当主线程的代码执行完毕,会检查微任务队列里面是否有代码没执行,有代码的话就一并执行,若是没有,宏任务队列里面的代码会依次进入主线程,直到宏任务为空。这样一分析,代码的执行顺序就很清晰了,分别是1 3 4 2 5。node
(1)全部同步任务都在主线程上执行,造成一个 执行栈 。
(2)主线程以外,还存在一个"宏任务队列" 。只要异步任务有了运行结果(例如定时器的时间到了,或者ajax请求回来数据了等等),就在"宏任务队列"之中放置一个事件(对应的回调函数)。
(3)一旦"执行栈"中的全部同步任务执行完毕,系统就会读取"微任务队列"里面的任务,微任务执行完,再看看"宏任务队列"里面有哪些事件。那些对应的异步任务,因而结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。ajax
上面一直在说微任务,宏任务,当前执行栈,浏览器怎么能知道何时执行宏任务,何时执行微任务,其实有一个这样的机制不断检查是否该执行微任务了,或者宏任务。(这是个很是简易的描述了,实际上会复杂不少)而这样的操做就被称为Event Loop。promise
* | 浏览器 | node |
---|---|---|
I/O | ✅ | ✅ |
setTimeout | ✅ | ✅ |
setInterval | ✅ | ✅ |
setImmediate | ❌ | ✅ |
requestAnimationFrame | ✅ | ❌ |
* | 浏览器 | node |
---|---|---|
Promise.then catch finally | ✅ | ✅ |
process.nextTick | ❌ | ✅ |
MutationObserver | ✅ | ❌ |