异步知识点
如何理解异步
异步是指程序在执行耗时操作(I/O、定时器、网络请求等)时,不会阻塞当前执行流程,而是将耗时操作委托给宿主环境(浏览器 / Node)处理,主线程继续执行后续代码;当耗时操作完成后,会通过「回调」通知主线程,主线程空闲时再执行对应的回调逻辑
为什么 JS 要设计成单线程?
JS 最初为了操作 DOM,如果多线程同时改 DOM,会出现冲突、渲染错乱;单线程能保证 DOM 操作顺序可控、安全。
异步 + 事件循环,解决单线程阻塞卡顿问题
同步、异步区别?
同步:代码从上到下排队执行,后面等前面做完,会卡住主线程。
异步:耗时任务(请求 / 定时器)放后台等着,主线程继续往下走;完成后进队列,空闲再回头执行。
宏任务、微任务分别有哪些?
宏任务:setTimeout/setInterval、I/O 操作、DOM 事件、requestAnimationFrame、fetch
微任务:Promise.then/catch/finally、async/await(底层是 Promise)、queueMicrotask、MutationObserver
async/await 和 Promise 的执行顺序有什么关系?
async/await 是 Promise 的语法糖:
- async 函数返回 Promise。
- await 后面的代码会被包装成 Promise.then,放入微队列
- 执行顺序:await 会暂停当前函数执行,让出主线程,等 Promise 决议后再将后续代码放入微队列
为什么 setTimeout (fn, 0) 不是立即执行?
- setTimeout 是宏任务,会被放入定时器队列,等待当前调用栈和微队列清空后才执行
- 即使延迟设为 0,也受浏览器最小延迟限制(通常 4ms),且需等待事件循环调度,所以无法真正「立即执行」
如何理解事件循环
JS 是单线程的,事件循环是处理异步任务的核心机制。我们可以把异步任务分为宏任务和微任务两类:
- 主线程先执行所有同步代码,直到调用栈为空
- 然后会优先清空所有微任务(比如 Promise.then、async/await),直到微任务队列完全为空
- 接着从宏任务队列里取出一个任务执行(比如 setTimeout、DOM 事件),执行完后再次回到第 2 步,清空微任务
- 如此循环往复,保证页面不被阻塞,同时高效处理异步逻辑
