【JS】JavaScript中的宏任务和微任务

目录

  • 概念
    • 宏任务
    • 微任务
  • 运行机制
  • 总结

js是一门单线程语言,所以它本身是不可能异步的,但是js的宿主环境(比如浏览器、node)是多线程,宿主环境通过某种方式(事件驱动)使得js具备了异步的属性。而在js中,我们一般将所有的任务都分成两类,一种是同步任务,另外一种是异步任务。而在异步任务中,又有着更加细致的分类,那就是微任务宏任务
【JS】JavaScript中的宏任务和微任务_第1张图片

概念

宏任务

宏任务:主代码块、setTimeout、setInterval、DOM事件、AJAX请求。

浏览器为了能够使得JS内部任务与DOM任务能够有序的执行,会在一个任务执行结束后,在下一个任务执行开始前,对页面进行重新渲染 。

微任务

微任务:Promise、async/await、process.nextTick。

微任务通常来说就是需要在当前 同步任务 执行结束后立即执行的任务,比如对一系列动作做出反馈,或者是需要异步的执行任务而又不需要分配一个新的任务,这样便可以减小一点性能的开销。

运行机制

console.log('整体script开始。');

setTimeout(()=>{
    console.log('宏任务setTimeout的回调函数。')
})

Promise.resolve().then(function() {
    console.log('微任务Promise回调函数1。')
}).then(function() {
    console.log('微任务Promise回调函数2。')
})


console.log('整体script结束。')

【JS】JavaScript中的宏任务和微任务_第2张图片
可以看到promise1和promise2在setTimeout之前打印,它们不都是异步任务吗?不应该setTimeout先进入任务队列等待执行吗?

JS引擎线程首先执行主代码块。

每次执行栈执行的代码就是一个宏任务,包括任务队列(宏任务队列)中的,因为执行栈中的宏任务执行完会去取任务队列(宏任务队列)中的任务加入执行栈中,即同样是事件循环的机制。

在执行宏任务时遇到Promise等,会创建微任务(.then()里面的回调),并加入到微任务队列队尾。

也就是说,在某一个宏任务执行完后,在重新渲染与开始下一个宏任务之前,就会将在它执行期间产生的所有微任务都执行完毕(在渲染前)。

我们来理一下上述程序运行过程:
1、整个代码块作为宏任务运行,最先运行。(不是说微任务优先吗?因为此时微任务队列为空啊)
2、遇到setTimeout时,将其交给webapi,虽然没有设置延时,但是浏览器规定最低4ms,4ms后,setTimeout的回调进入宏任务队列中,等待被调用。
3、遇到Promise后,交给webapi处理,因为直接resolve了,所以将then的回调函数放入微任务队列中。
4、此时第一个宏任务(最外层代码块)执行完成,输出"整体script结束。",注意此时,系统会先去微任务队列中取出任务依次放到执行栈中执行。也就是promise的两个回调函数,所以依次输出promise1和promise2。
5、promise1和promise2输出以后,代表这此时微任务队列为空,系统才会去宏任务中取出第一条宏任务执行,此时输出setTimeout。

总结

1、微任务是在宏任务的执行中产生的,所以一开始程序执行时是没有微任务的。
2、系统将微任务执行完以后,才会去执行下一个宏任务。
3、宏任务里如果有宏任务,不会执行里面的那个宏任务,而是被丢进任务队列后面,所以会最后执行。
4、宿主环境提供的属于宏任务:例如setTimeout。由语言标准提供的属于微任务:例如promise.then。可以以此来区分宏任务和微任务。

一张图片描述运行机制:
【JS】JavaScript中的宏任务和微任务_第3张图片

你可能感兴趣的:(我好像不会JavaScript,event,loop,微任务,宏任务,js)