在说这个问题之前,要先了解一下,什么是“同步任务”和“异步任务”:
JavaScript是一门单线程的语言,任务需要按照执行顺序来完成,下一个任务需等待上一个任务结束后才开始执行,这就是同步任务。
异步任务指任务执行后,不需要等待结果返回,也可以继续往下执行,当异步任务结果返回后会调用预先设置的监听函数执行后续任务。
上面已经说倒js是一门单线程语言,所以它本身是不可能异步的,但是js的宿主环境(比如浏览器、node)是多线程,宿主环境通过某种方式(事件驱动)使得js具备了异步的属性。
JavaScript引擎通过事件循环机制分别执行同步任务和异步任务。
其中“异步任务”可分为宏任务(macrotask)和微任务(microtask)
(下图是知乎上大神写的一篇文章里的,文章链接在文末)
宏任务:
主代码块
setTimeout
setInterval
Dom事件
ajax请求
setImmediate (Node独有)
requestAnimationFrame (浏览器独有)
I/O(node.js)
UI rendering (浏览器独有)
浏览器为了能够使得JS内部任务与DOM任务能够有序的执行,会在一个任务执行结束后,在下一个任务执行开始前,对页面进行重新渲染 。
微任务:
promise.then.catch.finally
mutationsObserve
objectObserve(已废除;Proxy对象代替)
process.nextTick(node.js)
微任务通常来说就是需要在当前 同步任务 执行结束后立即执行的任务,比如对一系列动作做出反馈,或者是需要异步的执行任务而又不需要分配一个新的任务,这样便可以减小一点性能的开销。
js事件循环:
当JavaScript引擎运行代码时,便开启第一轮事件循环,首先执行所有同步代码,其中可能产生一系列的宏任务和微任务并放到相应的队列中等待执行,当所有同步代码执行完毕,还未结束本轮事件循环,需要把本轮产生的微任务都执行完毕,如果执行微任务过程中又产生了宏任务和微任务,那么宏任务会放到宏任务队列中等待,微任务加入本轮微任务队列的末尾,等前面的微任务执行完毕就会立刻执行,只有当微任务队列为空时,才会执行宏任务队列中的第一个任务,开启下一轮的事件循环,宏任务中产生的宏任务还是放到宏任务队列,微任务放到微任务队列中等所有同步代码执行完毕后立刻执行,再执行下一个宏任务开启下一轮事件循环……
学习文档:https://zhuanlan.zhihu.com/p/474396841
https://blog.csdn.net/ZHANGYANG_1109/article/details/123839466