返回

前人栽树,后人乘凉!比较「宏任务」、「微任务」和「Promise」的奇妙执行秩序

前端

时光深处看异步

异步编程,顾名思义,就是指代码不是按照顺序执行,而是需要等待某些事件发生后才会继续执行。

在 JavaScript 中,我们常用的异步编程方法有:

  • setTimeout :用于延迟执行某个函数。
  • Promise :用于处理异步操作的结果。

异步编程小迷思

现在,我们来回答一个有趣的问题:

setTimeout和Promise,谁会先执行?

不少朋友可能会脱口而出:“Promise会先执行,因为它属于微任务,而setTimeout属于宏任务”。

但事实真的如此吗?带着这个疑问,我们一起开启一场异步编程的探索之旅吧!

宏任务和微任务的二重奏

JavaScript 引擎中有一个任务队列,用于存储需要执行的任务。任务队列分为宏任务队列和微任务队列。

宏任务队列:存放宏任务,如 setTimeout、setInterval 等。

微任务队列:存放微任务,如 Promise.then、MutationObserver 等。

轮番登场的执行顺序

宏任务和微任务的执行顺序如下:

  1. JavaScript 引擎先执行主线程中的同步任务。
  2. 当主线程执行完同步任务后,会检查是否有宏任务需要执行。
  3. 如果有宏任务需要执行,则将其放入宏任务队列。
  4. JavaScript 引擎从宏任务队列中取出一个宏任务,并将其执行。
  5. 执行完宏任务后,JavaScript 引擎会检查是否有微任务需要执行。
  6. 如果有微任务需要执行,则将其放入微任务队列。
  7. JavaScript 引擎从微任务队列中取出一个微任务,并将其执行。
  8. 重复步骤 5 和 6,直到微任务队列为空。
  9. 返回主线程,继续执行后续的同步任务。

Promise的“微”妙之处

Promise 是一个用来处理异步操作的JavaScript对象。Promise 有三个状态:

  • 等待(pending):初始状态,表示异步操作尚未完成。
  • 已完成(fulfilled):表示异步操作已成功完成。
  • 已拒绝(rejected):表示异步操作已失败。

当一个 Promise 对象处于等待状态时,我们会注册一个回调函数,以便在 Promise 完成时执行该回调函数。

我们把 Promise 的回调函数称为“微任务”,微任务会在当前任务完成(不管是宏任务还是微任务)后立即执行。

当“快”与“慢”相遇

现在,我们来回答文章开头的那个问题:

setTimeout和Promise,谁会先执行?

答案是:取决于 setTimeout 的执行时间。

如果 setTimeout 的执行时间小于 Promise 的执行时间,那么 setTimeout 会先执行。反之,Promise 会先执行。

这是因为 setTimeout 是宏任务,而 Promise 是微任务。宏任务和微任务的执行顺序是:宏任务先执行,微任务后执行。

微任务的异步惊喜

Promise 的微任务特点带给我们一些有趣的现象:

  1. Promise 链式调用 :可以将多个 Promise 对象串联起来,形成一个Promise链。当一个 Promise 对象完成时,会触发下一个 Promise 对象的执行。
  2. Promise 并发执行 :可以同时执行多个 Promise 对象。当所有 Promise 对象都完成时,再执行后续的操作。

这些特性使Promise成为处理异步操作的利器。

异步编程的奇妙世界

了解了宏任务、微任务和 Promise 的执行顺序后,我们对 JavaScript 的异步编程有了更深入的理解。在实践中,我们经常会用到setTimeout、Promise和其他异步编程技术。希望大家都能熟练掌握这些技术,并编写出优雅的异步代码。

结语

宏任务和微任务是 JavaScript 异步编程的基石,了解它们之间的区别和执行顺序,可以帮助我们更好地理解和使用异步编程技术。而 Promise 是一个强大的异步编程工具,掌握它可以使我们的代码更加简洁和高效。