面试中经常会被问到什么宏任务和微任务?工作中也会出一个奇怪的问题,两行代码,一会
A
结果现出来,一会B
结果先出来,搞得一头雾水。有些人为了懒省事,全都是用async await
,亦或者写个setTimeout
,也不去追究原理,能解决问题就行。接下来就对这个问题展开讨论。
什么是宏任务和微任务?
宏任务是由宿主(浏览器、Node
)发起的,一般在JavaScript
引擎空闲时执行(不知道这样说合不合理)。常见的宏任务有:setTimeout
、setInterval
、Ajax
、DOM事件
。
微任务是指在当前任务执行结束后立即执行的任务。常见的微任务有:Promise
、async/await
。其中Promise
本身是同步的,.then/.catch
才是异步的。
执行顺序
首先,在JavaScript
中,任务分为同步任务和异步任务,异步任务又有宏任务和微任务。同步任务在主线程中,异步任务会进入任务队列。
同步任务 》微任务 》宏任务
一起来看一下下面这个例子:
js
console.log(1);
setTimeout(() => {
console.log("setTimeout");
}, 1000);
new Promise((resolve, reject) => {
console.log("Promise1");
resolve("resolve");
console.log("Promise2");
}).then((data) => {
console.log(data);
});
console.log(2);
先区分一下都是什么任务:
按照上面的顺序,依次输出1
、Promise1
、Promise2
、2
、resolve
、setTimeout
,这里值得说一下Promise
本身是同步的,.then/.catch
才是异步的,所以会先输出Promise1
,而resolve("resolve")
是告诉Promise
成功了,并不阻碍进程,所以会继续输出Promise2
。
可能有人会说setTimeout
一秒后才执行,肯定最后输出了,再看一个例子,把setTimeout
设置为0,应该会立即执行吧?:
js
console.log(1);
setTimeout(() => {
console.log("setTimeout");
}, 1000);
setTimeout(() => {
console.log("setTimeout0");
}, 0);
new Promise((resolve, reject) => {
console.log("Promise1");
resolve("resolve");
console.log("Promise2");
}).then((data) => {
console.log(data);
});
console.log(2);
也是先分析都是什么任务,依次输出1
、Promise1
、Promise2
、2
、resolve
、setTimeout0
、setTimeout
,虽然setTimeout
设置为0,他也是宏任务,按照执行顺序,也是要排队的。
再看一个例子:
js
console.log(1);
setTimeout(() => {
console.log("setTimeout");
}, 10);
console.log(2);
for (let index = 0; index < 10000; index++) {
console.log(10000);
}
定时器设置10毫秒,下面循环10000次,肯定会超过10毫秒了,应该会先输出setTimeout
了吧,实时并不是这样,因为for
是同步的,但是JavaScript
引擎一直在忙没空去搭理它。
总结
JavaScript
中的任务分为同步任务和异步任务,异步任务又有宏任务和微任务;JavaScript
先查找同步任务,然后再去任务队列中查找微任务,最后才去任务队列中查找宏任务;- 执行顺序:同步任务 》微任务 》宏任务。