JavaScript中,异步方法执行时机是什么时候?
在JavaScript中,异步方法的执行时机取决于多种因素,主要是事件循环(Event Loop)和任务的类型(如宏任务、微任务)。
理解这些概念对于掌握异步编程至关重要。
事件循环(Event Loop)
JavaScript是单线程的,这意味着它一次只能执行一个任务。事件循环是用来处理异步操作(如定时器、网络请求、用户输入等)的机制。事件循环会不断地检查调用栈(Call Stack)是否为空,如果为空,则检查微任务队列(Microtask Queue),如果微任务队列也为空,则检查宏任务队列(Macrotask Queue),依次执行队列中的任务。
宏任务(Macrotask)
宏任务包括:
setTimeout()
setInterval()
- I/O 操作(如文件读写)
- UI 渲染
宏任务之间的切换由事件循环控制。每次事件循环迭代开始时,都会从宏任务队列中取出一个任务来执行。
微任务(Microtask)
微任务包括:
Promise
的回调(then
、catch
、finally
)MutationObserver
queueMicrotask()
微任务会在当前宏任务执行完成后、下一个宏任务执行之前立即执行。也就是说,一个宏任务执行完之后,会先清空微任务队列中的所有任务,然后再开始执行下一个宏任务。
异步方法的执行时机示例
console.log('Start');setTimeout(() => {console.log('setTimeout');
}, 0);Promise.resolve().then(() => {console.log('Promise');
});console.log('End');
输出结果为:
Start
End
Promise
setTimeout
解释:
console.log('Start')
同步执行,立即输出 “Start”。setTimeout
被放入宏任务队列。Promise.resolve().then(...)
中的回调被放入微任务队列。console.log('End')
同步执行,立即输出 “End”。- 当前宏任务执行完毕,事件循环开始处理微任务队列,执行
Promise
的回调,输出 “Promise”。 - 微任务队列清空后,事件循环开始处理下一个宏任务,执行
setTimeout
的回调,输出 “setTimeout”。
总结
-
异步方法(如
setTimeout
、Promise
)不会立即执行,而是根据它们被放入的队列类型(宏任务或微任务)在适当的时候由事件循环调度执行。 -
宏任务之间的切换由事件循环控制,每次事件循环迭代会先执行微任务队列中的所有任务。
-
理解事件循环和任务的类型对于编写和理解异步JavaScript代码至关重要。