一、任务队列的概念
任务队列是JavaScript中实现异步编程的重要机制。在任务队列中,任务被分为两种类型:微任务和宏任务。在理解微任务和宏任务的区别之前,我们需要先了解任务队列的概念。
//伪代码
setTimeout(() => {
console.log('task1');
}, 0);
Promise.resolve().then(() => {
console.log('task2');
});
console.log('task3');
在上述代码中,我们可以看到三个任务:task1、task2和task3。但是,它们并不是同步执行的,而是按照任务队列中的顺序依次被加入队列中。即task1首先被加入队列,在等待指定的时间后执行;task2作为微任务先被加入队列,在当前执行栈执行完成后执行;task3被加入队列,等待之前的任务执行完成后执行。
二、微任务和宏任务的区别
相较于宏任务,微任务是一类运行时机更加早的任务。
1. 执行时机不同
当后台任务队列的执行栈为空时,JavaScript引擎会从任务队列中取出一个任务并执行。每当一个任务执行结束,引擎就会检查是否需要执行微任务队列中的任务。只有在当前宏任务执行结束后才会执行微任务的队列。
//伪代码
console.log('task1');
setTimeout(() => {
console.log('task2');
}, 2000);
Promise.resolve().then(() => {
console.log('task3');
});
console.log('task4');
在上面的代码中,task1和task4是宏任务,其中task2是在2秒钟后被执行的宏任务,task3是在当前Promise执行完成后被执行的微任务。代码的执行顺序是:task1->task4->task3->task2。
2. 存储方式不同
宏任务的存储方式是一个个保存在任务队列中的,而微任务不同,它们是存在于宏任务中的,也就是说每个宏任务都有一个微任务队列。
//伪代码
setTimeout(() => {
console.log('task1');
Promise.resolve().then(() => {
console.log('task2');
});
}, 0);
console.log('task3');
在上面的代码中,我们可以看到setTimeout函数中除了一个宏任务task1,还有一个微任务task2。当task1被取出来执行时,task2也会被执行。代码的执行顺序是:task3->task1->task2。
3. 稳定性不同
由于微任务在当前宏任务执行结束前执行,所以它的执行过程中可能会影响到后续宏任务的执行顺序和结果。而宏任务则不存在这种稳定性问题。
//伪代码
setTimeout(() => {
console.log('task1');
}, 0);
Promise.resolve().then(() => {
console.log('task2');
setTimeout(() => {
console.log('task3');
}, 0);
});
console.log('task4');
在上面的代码中,task1和task3是两个宏任务,task2是一个微任务。当JavaScript引擎执行到微任务task2时,它会加入setTimeout任务队列中,而此时我们并不能确定task1与task3到底哪一个先被执行,因此最后的执行结果也是不稳定的。
4. 举例说明
setTimeout(() => {
console.log('task1');
}, 0);
Promise.resolve().then(() => {
console.log('task2');
});
console.log('task3');
在上述代码中,task1是一个宏任务,task2是一个微任务,task3是另一个宏任务。会先执行task3,然后执行task2,最后是task1。
5. 微任务应用举例
微任务可以用来在事件循环的不同阶段间传递数据,并且能够帮助我们利用异步代码完成一些类似同步的任务。
function loadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
resolve(img);
};
img.onerror = (e) => {
reject(e);
};
img.src = url;
});
}
loadImage('https://picsum.photos/200/300').then((img) => {
console.log('图片下载完成', img.width, img.height);
}).catch((e) => {
console.log('图片下载失败', e);
});
console.log('图片下载开始');
在上述代码中,我们首先创建了一个Promise对象,将图片加载操作放在Promise的构造函数中,并将Promise对象返回。当该Promise执行成功后,会在当前宏任务执行结束前被划分为一个微任务,最后在当前宏任务执行完成后输出结果。
三、结尾与总结
通过以上的介绍,我们了解了微任务和宏任务的定义、执行时机、存储方式、稳定性等差异。在实际开发过程中,我们可以应用这些知识来更好地利用异步编程,提高程序的效率。
原创文章,作者:OJGRB,如若转载,请注明出处:https://www.506064.com/n/361882.html