# 33、任务队列
# JS的定义
JS是一种单线程的语言,这样就意味着同一时间只能完成一件事。在代码中,JS引擎只能在单一线程中处理一次语句。
# 异步运行机制
callback、setTimeOut、ajax
等都是通过 事件循环(envent loop)
来实现的;
# 什么是Event Loop
主线程运行的时候,产生堆和栈,栈中的代码调用各种API,分发宏任务到任务队列当中,
event Loop
会一直运行,来执行进入队列的宏任务。一个event Loop
有多种的宏任务来源。但是浏览器每次都会选择一个源中的一个宏任务去执行。
# 宏任务(task)
宏任务
浏览器为了能够使JS内部task
与DOM
任务之间有序的进行,会在一个task
执行结束之后,在下一个task
执行开始之前,对页面进行重新渲染(task
->渲染->task
->渲染->....)
如:鼠标点击会触发一个时间回调,需要执行一个宏任务,然后解析HTML
。
还有setTimeout,setTimeout
的作用是等待给定的时间后为它的回调产生一个新的宏任务。
# 微任务(Microtasks)
微任务
微任务通常来说就是要在当前task
执行结束后立即执行的任务,比如对一系列动作做出的反馈,或者是需要异步的执行任务而又不需要分配一个新的task
,这样便可以减小一点性能的开销。只要执行栈中没有其他的JS代码正在执行且每个宏任务执行完,微任务队列会立即执行。如果在微任务执行期间微任务队列加入了新的微任务,会将新的微任务加入队列的尾部,之后也会被执行。所有微任务执行的时候,当前执行栈的代码必须已经执行完毕。
如:mutation observe
的回调
还有promise
的回调
# 完整的事件循环
# 总结
总结
宏任务按照顺序执行,且浏览器在每个宏任务之间渲染页面 所有微任务也按照顺序执行,且在以下场景会立即执行所有微任务
- 每个回调之后且
JS
执行栈中为空 - 每个宏任务结束后
注意: 同步任务执行完成后会先检查微任务队列中是否有任务执行,有的话就挨个执行,没有的话就开始检查宏任务队列中是否有任务,开始执行。
# 事件循环在node中和浏览器中的区别
区别
Node中分好多个阶段,每个阶段都相当于一个宏任务,依次执行。
timers
阶段:这个阶段执行timer(setTimeout、setInterval)
的回调I/O callbacks
阶段:处理一些上一轮循环中的少数未执行的I/O
回调idle, prepare
阶段:仅node
内部使用poll
阶段:获取新的I/O
事件, 适当的条件下node
将阻塞在这里check
阶段:执行setImmediate()
的回调close callbacks
阶段:执行socket
的close
事件回调
上面六个阶段都不包括 process.nextTick()
node10以前:执行一个阶段的所有任务,再执行nextTick
队列里的任务,再执行这个阶段中产生的微任务。
node11之后:和浏览器做了统一