定义与概念
- 宏任务(Macro - Task):宏任务是浏览器或JavaScript运行环境中的一个较大的任务单元,通常包括一些比较耗时或者不那么紧急的操作。例如,
script
(整体脚本)、setTimeout
、setInterval
、I/O
操作(如Ajax请求)、postMessage
、MessageChannel
等都属于宏任务。它们构成了任务队列(Task Queue)中的主要部分,这些任务的执行顺序遵循一定的规则,在事件循环(Event Loop)中按顺序逐个被处理。 - 微任务(Micro - Task):微任务是一种相对较小、更紧急的任务,它们通常是在当前宏任务执行结束后,下一个宏任务开始之前需要立即执行的任务。常见的微任务包括
Promise.then()
、MutationObserver
、process.nextTick
(在Node.js环境下)等。微任务队列(Micro - Task Queue)用于存储这些微任务,并且在宏任务执行间隙优先清空微任务队列。
- 宏任务(Macro - Task):宏任务是浏览器或JavaScript运行环境中的一个较大的任务单元,通常包括一些比较耗时或者不那么紧急的操作。例如,
执行顺序与时机
- 宏任务执行顺序:在JavaScript的单线程执行模型中,首先执行全局
script
代码,这是第一个宏任务。当这个宏任务执行过程中遇到异步的宏任务(如setTimeout
),会将其回调函数添加到宏任务队列的末尾。只有当当前宏任务以及微任务队列都为空时,才会从宏任务队列中取出下一个宏任务执行。例如:console.log('Script start'); setTimeout(() => { console.log('Timeout 1'); }, 0); setTimeout(() => { console.log('Timeout 2'); }, 0); console.log('Script end');
- 在这个例子中,首先执行
script
这个宏任务,打印Script start
,然后遇到两个setTimeout
,它们的回调函数被添加到宏任务队列。接着打印Script end
,此时当前宏任务结束。由于微任务队列没有任务,所以开始从宏任务队列中取出任务执行,先执行第一个setTimeout
的回调函数打印Timeout 1
,再执行第二个setTimeout
的回调函数打印Timeout 2
。 - 微任务执行顺序:在每个宏任务执行结束后,JavaScript引擎会立即检查微任务队列。如果微任务队列中有任务,会按照先进先出(FIFO)的顺序依次执行这些微任务,直到微任务队列清空。例如:
console.log('Script start'); const promise1 = Promise.resolve(); promise1.then(() => { console.log('Promise 1'); }); const promise2 = Promise.resolve(); promise2.then(() => { console.log('Promise 2'); }); console.log('Script end');
- 在这里,首先执行
script
宏任务,打印Script start
。然后promise1
和promise2
的.then
回调函数作为微任务被添加到微任务队列。接着打印Script end
,此时当前宏任务结束,开始执行微任务队列中的任务,按照添加顺序先打印Promise 1
,再打印Promise 2
。
- 宏任务执行顺序:在JavaScript的单线程执行模型中,首先执行全局
对应用性能和行为的影响
- 宏任务对性能的影响:由于宏任务相对比较耗时,过多的宏任务或者长时间运行的宏任务可能会导致页面的延迟和卡顿。例如,一个复杂的
setInterval
定时器在每次执行回调函数时进行大量的计算或者DOM操作,可能会占用较长的时间,使得后续的任务(包括渲染任务)被延迟。特别是当宏任务中包含I/O操作(如网络请求)时,等待响应的时间可能会不确定,这也会影响整个应用的响应性能。 - 微任务对性能的影响:微任务通常用于处理一些对及时性要求较高的操作,它们的执行相对比较快速。但是,如果微任务队列中的任务过多或者某个微任务执行时间过长,也可能会阻塞下一个宏任务的执行,从而影响到整个事件循环的节奏。不过,由于微任务本身是在宏任务间隙执行的,所以在合理使用的情况下,它们可以帮助我们在不阻塞主要任务流程的情况下及时处理一些小的、重要的操作,如更新UI状态等。
- 应用行为方面的差异:在应用行为上,宏任务更适合用于处理一些可以延迟执行或者周期性执行的任务,如定时更新数据、延迟加载资源等。而微任务则常用于在异步操作完成后立即进行一些后续处理,并且这些处理通常与当前的执行上下文紧密相关,如在
Promise
成功或失败后立即进行相应的状态更新或者错误处理。例如,在一个基于Promise
的异步数据加载应用中,使用微任务来更新UI显示加载成功的数据,能够确保在数据加载完成后及时、同步地更新界面,提供更好的用户体验。
- 宏任务对性能的影响:由于宏任务相对比较耗时,过多的宏任务或者长时间运行的宏任务可能会导致页面的延迟和卡顿。例如,一个复杂的