在熟悉宏任务,微任务之前,需要先回忆一个名词:事件循环👊
什么是事件循环?
只要一问这些概念性的东西,总是一脸懵的尴尬,然后开始心底没底的表述就是常说的宏任务、微任务,只想着把注意力引到自己熟悉的地方。
那怎样理解,怎样回答才是最优解呢?
最简洁的描述:一种机制,负责管理任务的调度和执行。
为何需要这种机制?
老生常谈的单线程语言一次只能执行一个任务,
但在实际应用中,我们需要处理很多异步任务,例如网络请求、定时器、事件处理等。
这就是事件循环的作用,它确保异步任务按照正确的顺序执行。
1、什么是宏任务,微任务?
- 宏任务:一个较大的任务单元。
- 微任务:一个较小的任务单元。
2、宏任务、微任务常见有哪些?
宏任务:
- script(JS 整体代码)、setTimeout、setInterval、I/O、UI 交互
微任务:
- Promise 回调:当一个 Promise 的状态变为 resolved 或 rejected 时,与之关联的回调函数会被放入微任务队列。
3、为什么会出现微任务?
微任务的出现其实就是语言设计中的一种实时性和效率的权衡体现。当宏任务执行时间太久,就会影响到后续任务的执行,而此时因为某些需求,突然有高优先级的任务需要尽快执行。(从此处可知在事件循环的设计中,微任务被赋予了更高的优先级,优先执行)
4、那浏览器环境与node环境执行宏任务、微任务是否存在区别?
- node 中事件循环的实现依赖 libuv 引擎,它有一套自己的循环机制
- node10之后的版本,几乎与浏览器保持一致
5、事件循环的基本流程如下
- 执行当前宏任务(从宏任务队列中取出一个任务执行)。
- 执行所有微任务(从微任务队列中取出并执行所有微任务)。
渲染页面更新(如果需要)。
- 进入下一个事件循环。
6、基于案例执行
- 所有代码(JS 整体代码)作为宏任务进入主线程执行栈执行
- 执行过程中,同步代码立即执行。遇到微任务,将其添加至微任务队列中。遇到宏任务,将其添加到宏任务队列中
- 当前宏任务出队完成,读取微任务队列,直到执行完所有微任务( 即微任务队列为空 )。本轮宏任务执行完成
- 队列若存在宏任务,出队回到步骤2,继续循环执行,直到宏任务队列清空
案例:
function taskOne() {
console.log('task one ...')
setTimeout(() => {
Promise.resolve().then(() => {
console.log('task one micro in macro ...')
})
setTimeout(() => {
console.log('task one macro ...')
}, 0)
}, 0)
taskTwo()
}
function taskTwo() {
console.log('task two ...')
Promise.resolve().then(() => {
setTimeout(() => {
console.log('task two macro in micro...')
}, 0)
})
setTimeout(() => {
console.log('task two macro ...')
}, 0)
}
setTimeout(() => {
console.log('running macro ...')
}, 0)
taskOne()
Promise.resolve().then(() => {
console.log('running micro ...')
})
补充说明
面试遇到类似输出题目,别紧张,基于队列的先入先出规则,列出列队中的任务,
不要盲目自信依赖大脑的记忆力,不然会造成其实你会,只是记忆断片了,忘记队列里哪个是先进去的导致的尴尬场景~
1、宏任务队列
2、微任务队列
3、输出结果