异步编程的核心是避免阻塞主线程而非提速;settimeout(0)仍需等待调用栈清空,属宏任务;回调本质是控制权反转;async/await是promise的线性封装,非自动异步;关键在厘清逻辑依赖关系。

异步编程不是“让代码跑得更快”,而是“不让它卡住主线程”——这是所有初学者最该立刻建立的认知。
为什么 setTimeout(() => {}, 0) 不是“立刻执行”?
很多人以为 setTimeout 设为 0 毫秒就能绕过同步阻塞,结果发现日志还是排在同步代码之后。这是因为 Event Loop 的调度机制:即使延时为 0,回调也会被推入任务队列,等当前调用栈清空后才执行。
- 同步代码(如
console.log('A'))直接压栈、立即执行 -
setTimeout的回调属于宏任务,必须等本轮同步任务全部结束才轮到它 - 浏览器中最小延时约 4ms(HTML5 规范限制),Node.js 约为 1ms,但实际仍受事件循环节拍影响
回调函数不是“多写个函数”,而是交出控制权
把函数当参数传给 fs.readFile 或 fetch,不是为了“看起来高级”,而是告诉运行时:“等你搞定这件事,再调我这个函数”。这叫控制权反转(IoC)——主流程不再决定何时继续,而由 I/O 完成事件触发。
- 常见错误:在回调里写大量嵌套逻辑,导致缩进失控、错误难追踪(即“回调地狱”)
- 正确姿势:回调只做三件事——检查
err、处理数据、调用下一个明确的函数(比如render(data)) - Node.js 中很多 API(如
fs.readFile)仍保留回调签名,但现代写法应优先用fs.promises.readFile
async/await 不是语法糖,而是对 Promise 链的线性封装
写 async function 并不自动让函数变“异步”,它只是让内部 await 能暂停执行并交还控制权;函数本身返回的是 Promise,调用者仍需用 .then() 或外层 await 处理。
- 容易踩坑:在非 async 函数里写
await→ 报错SyntaxError: await is only valid in async functions - 常见误用:
await fetch(url).then(...)—— 这样写了两层异步,其实await fetch(url)就够了 - 注意兼容性:IE 完全不支持
async/await,若需兼容,得用 Babel 编译或退回 Promise 写法
真正难的从来不是记住 await 怎么写,而是判断某段逻辑是否该放进异步流——比如一个表单提交后要更新 UI、发请求、再弹提示,这三步谁依赖谁、谁必须等谁,稍一错位就会出现 UI 闪动、状态错乱或重复提交。这才是异步思维落地时最常卡住的地方。











