1. 什么是宏任务和微任务
JavaScript 把异步任务又做了进一步的划分,异步任务又分为两类,分别是:
① 宏任务(macrotask
): 宿主环境提供的异步方法都是宏任务
- script全部代码
- 异步 Ajax 请求
setTimeout、setInterval
- 文件操作
DOM事件
I/O
UI
rendering
② 微任务(microtask
):语言标准提供
Promise
Async / Await
mutationObserver
Process.nextTick(Node独有)
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. 宏任务和微任务的执行顺序
- 每一个宏任务执行完之后,都会检查是否存在待执行的微任务,
- 如果有,则执行完所有微任务之后,再继续执行下一个宏任务。
- 当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行。
六、Event Loop执行顺序
- JS是单线程的,按照顺序一行一行执行,如果某行报错则停止后续执行,然后就是「先执行同步,再执行异步」,
- 看图,我们会将同步代码一行一行放入
Call Stack
中执行, - 遇到异步代码就记录一下,在此过程中异步代码如果是宏任务移动到
Web APIs
,直到定时的时间到就放入任务队列,即图中的Callback Queue
。 - 如果是微任务则放入微任务队列,即图中的
Mirco Task Queue
。Promise
是ES6
规范的,不是W3C规范的所以不会经过Web APIs
。 - 如果同步代码执行完,调用栈
Call Stack
为空,去查看微任务队列,每执行完一个微任务,它就会从微任务队列出队, - 直到微任务队列清空后,「这时候首先会尝试DOM渲染,之后再触发
Event Loop
机制」,(如果DOM结构发生变化)。 - 然后
Event Loop
开始工作,然后轮询查找Callback Queue
,如有则移动到Call Stack
执行... 每执行完一个宏任务,就会去检查微任务队列,若微任务队列有,就执行到微任务为空,再尝试DOM渲染,然后去看宏任务队列,继续轮询查找。
❝ 请注意:为什么是尝试DOM渲染,因为可能这一段JS代码里并没有修改DOM,尝试是代表着如果有对DOM的操作,那么去渲染,没有的话,忽略这一步。❞