宏任务和微任务
异步回调的概念
异步回调有两种方式
- 把异步回调函数封装成一个宏任务,添加到消息队列尾部,当循环系统执行到该任务的时候执行回调函数–如 setTimeout 和 XMLHttpRequest的回调函数
- 主函数执行结束后,
当前宏任务结束之前
执行回调函数,这通常都是微任务
宏任务
宏任务类型
- 渲染事件(解析DOM、计算布局、绘制)
- 用户交互事件(鼠标点击、滚动页面、放大缩放等)
- js脚本执行事件
- 网络请求完成、文件读写完成事件
- setTimeout setInterval
定义
为了协调这些任务有条不紊地在主进程执行,引入了消息队列
和事件事件循环
渲染进程内部维护多个
消息队列,比如延迟执行队列
和普通的消息队列
然后主进程采用一个for循环,不断地从这些任务队列中取出任务并执行任务。
这些就是宏任务
事件循环的流程
- 先从多个消息队列中选出一个最老的任务,这个任务称为oldestTask;
- 然后循环系统记录任务开始执行的事件,并把这个oldestTask设置为当前正在执行的任务;
- 当任务执行完成之后,删除当前正在执行的任务,并从对应的消息队列中删除这个oldestTask;
- 最后统计执行完成的时长等信息
宏任务的缺点
- 难以胜任时间精度要求高的场景以上代码:
1
2
3
4
5
6
7
8function timerCallback2(){
console.log(2)
}
function timerCallback(){
conole.log(1)
setTimeout(timerCallback2,0)
}
setTimeout(timerCallback,0)
在调用setTimeout来设置回调任务的间隙,消息队列中就有可能就被插入很多系统级
的任务。导致第二次的setTimeout可能延后很多
微任务
定义:微任务就是一个需要异步执行的函数
,执行时机是在主函数执行结束之后、当前宏任务结束之前
。
如何运转
V8创建一个全局执行上下文
,同时创建一个微任务队列
。这个微任务队列是给V8引擎内部使用的,所以你无法通过js直接访问。
如何产生微任务
MutationObserver
监控某个节点,然后通过js修改这个节点,或者为这个节点添加删除部分子节点,当DOM节点发生变化时,就会产生DOM节点变化记录的微任务
Promise
当调用 Promise.resolve() 或者 Promise.reject() 的时候,也会产生微任务。
执行时机
当前宏任务中的javaScript快要执行完成时
,js引擎准备退出全局执行上下文并清空调用栈的时候
,js引擎会检查全局执行上下文中的微任务队列,按顺序执行。ps:还有别的检查点