JS 事件循环

Event loop

JS 事件循环

 

 

 在上图中可以看到,setTimeout这类异步接口实际上不在JS引擎中,而是由浏览器中的Web(图中的V8是chrome中的JS引擎,safari、firefox则是各自的引擎,参考《主流浏览器内核及JS引擎》)

setTimeout(() => 
  console.log(1)
}, 0)

console.log(0)

执行的过程:

  • 然后「JS引擎线程」执行了console.log(0),控制台中输出了0

  • 浏览器中的「定时器线程」接管该定时任务,当定时任务超时后,将回调函数即console.log(1)塞入到宏任务队列中,等待调度,如图中「2」

  • 「event loop线程」检查JS执行栈是否为空,如果是,则将宏任务队列中的任务塞入JS执行栈中,如图中「8」

  • 「JS引擎线程」处理执行栈中的console.log(1)代码,控制台中输出1

从这个流程可以看出,无论超时设置的多短,setTimeout中的回调函数必须等到下一次事件循环才能被处理,这就不难理解为什么0会在1之前输出了

 

promise.then函数

Promise.resolve().then(()=>{
   console.log(2) 
})

console.log(0)

执行的过程:

  • 「JS引擎线程」运行JS执行栈中执行如上代码,由于Promise首先执行了resolve函数变为终结状态,因此立即执行promise.then方法,此方法实际上是创建了一个微任务,并将console.log(2)塞入微任务队列中,如图「5」所示。

  • 然后「JS引擎线程」执行了console.log(0),控制台中输出了0

  • 「event loop线程」检查JS执行栈是否为空,如果是,则将微任务队列中的任务塞入JS执行栈中,如图中「8」

  • 「JS引擎线程」处理执行栈中的console.log(2)代码,控制台中输出2

任务分类

JS事件循环中的任务分为两大类

  • 宏任务,即task

  • 微任务,即microTask,也称job

对于浏览器环境和Node环境,提供的接口会有些许差别

宏任务接口

接口 浏览器 Node
I/O操作 ? ?
setTimeout ? ?
setInterval ? ?
setImmediate ? ?
requestAnimationFrame ? ?

微任务接口

接口 浏览器 Node
process.nextTick ? ?
promise.then/catch/finally ? ?
MutationObserver ? ?

任务优先级

  • 整体上,微任务的处理优先于宏任务。准确的说是微任务会在本此事件循环结束前处理,宏任务会在下次事件循环开始时处理。

  • 在Node环境中,process.nextTick产生的微任务优先级最高,会被插到微任务队列的最前端优先处理;而setImmediate产生的宏任务优先级最高,会在所有宏任务之前执行

JS 事件循环

上一篇:基于微信红包插件的原理实现android任何APP自动发送评论(已开源)


下一篇:网页 HTML 自动播放下一首音乐