前人栽树,后人乘凉!比较「宏任务」、「微任务」和「Promise」的奇妙执行秩序
2023-11-15 14:36:02
时光深处看异步
异步编程,顾名思义,就是指代码不是按照顺序执行,而是需要等待某些事件发生后才会继续执行。
在 JavaScript 中,我们常用的异步编程方法有:
- setTimeout :用于延迟执行某个函数。
- Promise :用于处理异步操作的结果。
异步编程小迷思
现在,我们来回答一个有趣的问题:
setTimeout和Promise,谁会先执行?
不少朋友可能会脱口而出:“Promise会先执行,因为它属于微任务,而setTimeout属于宏任务”。
但事实真的如此吗?带着这个疑问,我们一起开启一场异步编程的探索之旅吧!
宏任务和微任务的二重奏
JavaScript 引擎中有一个任务队列,用于存储需要执行的任务。任务队列分为宏任务队列和微任务队列。
宏任务队列:存放宏任务,如 setTimeout、setInterval 等。
微任务队列:存放微任务,如 Promise.then、MutationObserver 等。
轮番登场的执行顺序
宏任务和微任务的执行顺序如下:
- JavaScript 引擎先执行主线程中的同步任务。
- 当主线程执行完同步任务后,会检查是否有宏任务需要执行。
- 如果有宏任务需要执行,则将其放入宏任务队列。
- JavaScript 引擎从宏任务队列中取出一个宏任务,并将其执行。
- 执行完宏任务后,JavaScript 引擎会检查是否有微任务需要执行。
- 如果有微任务需要执行,则将其放入微任务队列。
- JavaScript 引擎从微任务队列中取出一个微任务,并将其执行。
- 重复步骤 5 和 6,直到微任务队列为空。
- 返回主线程,继续执行后续的同步任务。
Promise的“微”妙之处
Promise 是一个用来处理异步操作的JavaScript对象。Promise 有三个状态:
- 等待(pending):初始状态,表示异步操作尚未完成。
- 已完成(fulfilled):表示异步操作已成功完成。
- 已拒绝(rejected):表示异步操作已失败。
当一个 Promise 对象处于等待状态时,我们会注册一个回调函数,以便在 Promise 完成时执行该回调函数。
我们把 Promise 的回调函数称为“微任务”,微任务会在当前任务完成(不管是宏任务还是微任务)后立即执行。
当“快”与“慢”相遇
现在,我们来回答文章开头的那个问题:
setTimeout和Promise,谁会先执行?
答案是:取决于 setTimeout 的执行时间。
如果 setTimeout 的执行时间小于 Promise 的执行时间,那么 setTimeout 会先执行。反之,Promise 会先执行。
这是因为 setTimeout 是宏任务,而 Promise 是微任务。宏任务和微任务的执行顺序是:宏任务先执行,微任务后执行。
微任务的异步惊喜
Promise 的微任务特点带给我们一些有趣的现象:
- Promise 链式调用 :可以将多个 Promise 对象串联起来,形成一个Promise链。当一个 Promise 对象完成时,会触发下一个 Promise 对象的执行。
- Promise 并发执行 :可以同时执行多个 Promise 对象。当所有 Promise 对象都完成时,再执行后续的操作。
这些特性使Promise成为处理异步操作的利器。
异步编程的奇妙世界
了解了宏任务、微任务和 Promise 的执行顺序后,我们对 JavaScript 的异步编程有了更深入的理解。在实践中,我们经常会用到setTimeout、Promise和其他异步编程技术。希望大家都能熟练掌握这些技术,并编写出优雅的异步代码。
结语
宏任务和微任务是 JavaScript 异步编程的基石,了解它们之间的区别和执行顺序,可以帮助我们更好地理解和使用异步编程技术。而 Promise 是一个强大的异步编程工具,掌握它可以使我们的代码更加简洁和高效。