1. 什么是宏任务和微任务
JavaScript 把异步任务又做了进一步的划分,异步任务又分为两类,分别是:
① 宏任务(macrotask): 宿主环境提供的异步方法都是宏任务
- script全部代码
- 异步 Ajax 请求
- setTimeout、setInterval
- 文件操作
- DOM事件
- I/O
- UI
- rendering
② 微任务(microtask):语言标准提供
- Promise
- Async / Await
- mutationObserver
- Process.nextTick(Node独有)
![异步任务][1]
2. Event Loop 和DOM渲染
console.log('script start');
setTimeout(() => {
console.log('setTimeout');
}, 0);
new Promise((resolve) => {
console.log('promise1');
resolve();
});
const div = document.createElement('div')
div.innerHTML = '<h1>hello</h1>'
document.body.appendChild(div);
alert('我是一个alert');
console.log('script end');// script start
// promise1
// 弹窗 我是一个alert DOM渲染
// script end
// setTimeout
> 由上面的执行结果可以看出DOM渲染是在微任务之后执行。DOM渲染后才会去执行宏任务;
3. 宏任务和微任务的根本区别
- 微任务是由ECMAscript 2015(ES6)语法规定的,
- 宏任务是由浏览器规定的。
4. 宏任务和微任务的执行顺序
![异步任务执行顺序.png][2]
- 每一个宏任务执行完之后,都会检查是否存在待执行的微任务,
- 如果有,则执行完所有微任务之后,再继续执行下一个宏任务。
- 当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行。
六、Event Loop执行顺序
![Event Loop执行顺序][3]
1. JS是单线程的,按照顺序一行一行执行,如果某行报错则停止后续执行,然后就是「先执行同步,再执行异步」,
2. 看图,我们会将同步代码一行一行放入Call Stack中执行,
3. 遇到异步代码就记录一下,在此过程中异步代码如果是宏任务移动到Web APIs,直到定时的时间到就放入任务队列,即图中的Callback Queue。
4. 如果是微任务则放入微任务队列,即图中的Mirco Task Queue。Promise是ES6规范的,不是W3C规范的所以不会经过Web APIs。
5. 如果同步代码执行完,调用栈Call Stack为空,去查看微任务队列,每执行完一个微任务,它就会从微任务队列出队,
6. 直到微任务队列清空后,「这时候首先会尝试DOM渲染,之后再触发Event Loop机制」,(如果DOM结构发生变化)。
7. 然后Event Loop开始工作,然后轮询查找Callback Queue,如有则移动到Call Stack执行...
8. 每执行完一个宏任务,就会去检查微任务队列,若微任务队列有,就执行到微任务为空,再尝试DOM渲染,然后去看宏任务队列,继续轮询查找。
> ❝ 请注意:为什么是尝试DOM渲染,因为可能这一段JS代码里并没有修改DOM,尝试是代表着如果有对DOM的操作,那么去渲染,没有的话,忽略这一步。❞
[1]: http://www.gonwe.cn/usr/uploads/2022/06/1978434904.png
[2]: http://www.gonwe.cn/usr/uploads/2022/06/3255431839.png
[3]: http://www.gonwe.cn/usr/uploads/2022/06/2321147548.png