关于事件循环及宏任务微任务的233事
由于需要操作DOM,限制了javaScript只能是一种单线程的语言,然而如果执行所有任务都是从上到下同步式的执行,在发送请求后,未得到数据返回前整个浏览器会处于“卡死”的状态,这样的用户体验极差。
为了解决这种情况,出现了异步的机制,而实现异步机制的方法就是事件循环(Event Loop)
首先来看下下面的案例
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
// script start
// script end
// promise1
// promise2
// setTimeout
首次接触事件循环的小伙伴看到上方案例输出的结果可能会有些疑惑,看完整篇文章再回头看看就会明白了
由于JavaScript是单线程,所以事件循环中所有任务都是排队执行的,并且根据任务类型分成了宏任务和微任务
宏任务:
宏任务指的是类似用户DOM操作、script(整体代码)、setTimeout、setInterval等代码执行都算在宏任务中,在一个宏任务执行完毕后会重新渲染,每当有宏任务产生,会将其添加到一个宏任务队列中,每次循环从队列中取出一个放入task中
微任务:
微任务一般来说会在宏任务执行完毕后执行,或者是在代码执行栈执行完毕后执行,比如对一系列动作做出反馈,或或者是需要异步的执行任务而又不需要分配一个新的 task,这样便可以减小一点性能的开销。
微任务一般指的是Promise、 MutaionObserver等异步函数的回调函数,当一个Promise有了结果(状态为fulfilled或rejected)时,会为其产生一个回调的微任务,每当有微任务产生也会将其放入微任务队列中。
知道了宏任务和微任务的概念后,我们再重新看下上面的案例
console.log('script start'); // 输出script start
setTimeout(function() { // 宏任务,放入宏任务队列
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1'); // 微任务,放入微任务队列
}).then(function() {
console.log('promise2'); // 微任务,放入微任务队列
});
console.log('script end'); // 输出 script end
代码从上到下执行,首先遇到了输出script start,接下来遇到了setTimeout,setTimeout属于宏任务的一种所以将其放入宏任务队列中,往下走遇到了Promise,Promise的状态为fulFilled,将两个回调函数按顺序放入微任务队列,往下走,输出script end,执行栈执行完毕,查看是微任务队列是否有任务,发现有两个微任务,全部执行,输出promise1,promise2,进入下一次事件循环中,查看宏任务队列,有待执行的宏任务,执行并输出setTimeout.
总结:
1、宏任务按顺序执行,且浏览器在每个宏任务之间渲染页面
2、所有微任务也按顺序执行,且在以下场景会立即执行所有微任务
- 每个回调之后且js执行栈中为空。
- 每个宏任务结束后。
才疏学浅,如有意见,请多指教