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 QueuePromiseES6规范的,不是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