返回

窥探JS异步任务执行奥秘:microtasks与macrotasks

前端

在JavaScript的世界中,我们经常会遇到异步编程,也就是代码不会按顺序执行的情况。这背后的原理是JavaScript引擎是单线程的,这意味着它一次只能执行一个任务。为了处理异步任务,JavaScript引入了microtasks和macrotasks的概念。

JavaScript单线程的工作方式

JavaScript引擎是单线程的,也就是说它一次只能执行一个任务。当JavaScript引擎开始执行一个函数时,它就会把这个函数执行完,只有执行完这段代码才会继续执行后面的代码。这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着。

JavaScript的微任务队列和宏任务队列

JavaScript引擎内部有两个队列:微任务队列和宏任务队列。微任务队列优先级更高,当微任务队列中的任务执行完毕后,才会执行宏任务队列中的任务。

微任务队列中的任务包括:

  • Promise.then() 和 Promise.catch() 回调函数
  • MutationObserver的回调函数
  • requestAnimationFrame() 回调函数
  • queueMicrotask() 调用的回调函数

宏任务队列中的任务包括:

  • setTimeout() 和 setInterval() 回调函数
  • script标签
  • I/O操作(如ajax请求)
  • UI渲染

微任务与宏任务的执行顺序

当JavaScript引擎执行代码时,它会先检查微任务队列中是否有任务需要执行。如果有,则会先执行微任务队列中的任务,然后再执行宏任务队列中的任务。

也就是说,在同一时间内,微任务队列中的任务会先于宏任务队列中的任务执行。

理解microtasks和macrotasks的意义

理解microtasks和macrotasks的执行顺序对于理解JavaScript异步编程非常重要。它可以帮助我们避免一些常见的错误,并编写出更加健壮的代码。

例如,如果我们在setTimeout()回调函数中使用Promise.then(),那么Promise.then()回调函数会在setTimeout()回调函数之前执行。这是因为Promise.then()回调函数是微任务,而setTimeout()回调函数是宏任务。

再比如,如果我们在requestAnimationFrame()回调函数中使用setTimeout(),那么setTimeout()回调函数会在requestAnimationFrame()回调函数之后执行。这是因为requestAnimationFrame()回调函数是微任务,而setTimeout()回调函数是宏任务。

总结

通过了解microtasks和macrotasks,我们可以更好地理解JavaScript异步编程。这可以帮助我们避免一些常见的错误,并编写出更加健壮的代码。