前言:理解宏任务和微任务前,先得理解两个过程,如下:
一、JavaScript执行过程
const name = "miracle";
console.log(name);
function sum(num1, num2) {
return num1 + num2;
}
function bar() {
return sum(20, 30);
}
const result = bar();
console.log(result);
分析上面代码的执行过程:
(1) 定义变量name;
(2) 执行log函数,函数会被放入到调用栈中执 行;
(3) 调用bar()函数,被压入到调用栈中,但是执行未结束;
(4) bar因为调用了sum,sum函数被压入到调 用栈中,获取到结果后出栈;
(5) bar获取到结果后出栈,获取到结果result;
(6) 将log函数压入到调用栈,log被执行,并且 出栈;
二、浏览器的事件循环过程
如果在执行JavaScript代码的过程中,有异步操作呢?
(1)中间我们插入了一个setTimeout的函数调用;
(2)这个函数被放到入调用栈中,执行会立即结束,并不会阻塞后续代码的执行;
const name = "miracle";
console.log(name);
function sum(num1, num2) {
return num1 + num2;
}
function bar() {
return sum(20, 30);
}
//加入异步函数
setTimeout(() => {
console.log("setTimeout");
}, 1000);
const result = bar();
console.log(result);
那么,传入的一个函数(比如我们称之为timer函数),会在什么时候被执行呢?
(1)事实上,setTimeout是调用了web api,在合适的时机,会将timer函数加入到一个事件队列中;
(2)事件队列中的函数,会被放入到调用栈中,在调用栈中被执行;
(3)下面是浏览器的事件循环过程图:
三、宏任务和微任务
但是事件循环中并非只维护着一个队列,事实上是有两个队列:
(1)宏任务队列(macrotask queue):ajax、setTimeout、setInterval、DOM监听、UI Rendering等
(2) 微任务队列(microtask queue):Promise的then回调、 Mutation Observer API、queueMicrotask()等
(3)那么事件循环对于两个队列的优先级是怎么样的呢?
1)main script中的代码优先执行(编写的顶层script代码);
2)在执行任何一个宏任务之前(不是队列,是一个宏任务),都会先查看微任务队列中是否有任务需要执行
3)也就是宏任务执行之前,必须保证微任务队列是空的;
4) 如果不为空,那么久优先执行微任务队列中的任务(回调)
四、补充部分
关注公众号:【深漂程序员小庄】:
内含丰富的学习资源和面试经验(不限前端、java),还有学习交流群可加,并且还有各大厂大佬可一起交流学习,一起进步~添加小庄微信,回复【加群】,可加入互联网技术交流群: