promise 是封装未来完成或失败异步操作的对象,非语法糖或同步魔法;它立即执行 executor,通过 .then/.catch 处理结果,链式调用返回新 Promise;async/await 是其语法糖,await 不阻塞线程但需 try/catch 捕错。

Promise 是什么,不是什么
Promise 不是语法糖,也不是让异步变同步的魔法。它是一个对象,用来封装一个**尚未完成但未来会完成(或失败)的异步操作**,并提供统一的 .then()/.catch() 接口处理结果。
常见误解是把它当“等待器”——new Promise() 立即执行 executor 函数,内部的异步逻辑(比如 setTimeout 或 fetch)才决定 resolve/reject 的时机。Promise 本身不暂停代码执行。
- 构造时传入的函数(executor)是同步运行的,但通常在里面启动异步任务
-
Promise.resolve(value)和Promise.reject(reason)用于快速创建已决议的 Promise - 链式调用中,每个
.then()返回的是**新 Promise**,值传递靠 return,错误传递靠 throw 或返回 rejected Promise
async/await 是 Promise 的语法糖,不是新机制
async 函数必定返回 Promise,哪怕你写 return 42,实际返回的是 Promise.resolve(42);await 只是让 js 引擎在遇到 Promise 时暂停当前 async 函数的执行,等它 settled 后再继续——它不阻塞线程,也不影响事件循环。
注意:await 只能在 async 函数内使用,顶层 await 仅在模块(type="module")中有效。
立即学习“Java免费学习笔记(深入)”;
-
await后面不强制是 Promise,非 Promise 值会被自动包装成 resolved Promise - 错误必须用
try/catch捕获,.catch()在 async 函数外才能接住抛出的异常 - 多个独立请求别用
await串行写,该用Promise.all([p1, p2])并发发
常见错误:混淆状态、忽略错误、滥用 await
最典型的问题是以为 await promise 能“修复”被 reject 的 Promise——其实它只是把 rejection 变成 throw,不 catch 就崩。
另一个高频坑是把本可并发的请求写成串行:
async function bad() { const a = await fetch('/api/a').then(r => r.json()); const b = await fetch('/api/b').then(r => r.json()); // 等 a 完了才发 b return [a, b]; }
正确做法是先发两个请求,再 await 它们的结果:
async function good() { const [a, b] = await Promise.all([ fetch('/api/a').then(r => r.json()), fetch('/api/b').then(r => r.json()) ]); return [a, b]; }
- 忘记处理 reject → 页面白屏或静默失败;加
try/catch或在最后链.catch(console.Error) - 在循环里直接 await → 实际是串行,性能差;需用
map().map(p => p.then(...))或Promise.allSettled() - 用
await包裹已执行完的 Promise → 没必要,纯属多绕一层
调试 Promise 链和 await 的实际技巧
chrome 和 firefox 控制台能显示 Promise 状态(pending/resolved/rejected),但不会显示中间 resolve 值。想看清每一步,要么加 console.log,要么用 async 函数拆分逻辑块。
node.js 中可通过 --trace-warnings 暴露未捕获的 Promise rejection;浏览器可用 window.addEventListener('unhandledrejection', ...) 兜底。
- 链式调用过长时,优先拆成小的
async函数,比堆.then().then().then()更易读 -
await Promise.resolve().then(...)是无效延迟,等同于直接执行;真要微任务延迟,用await Promise.resolve() - 测试时模拟 reject,别只 mock 成功路径;用
jest.mock或sinon.stub().rejects()覆盖错误分支
Promise 和 async/await 的核心差异不在能力,而在表达力与错误流控方式。真正卡住人的,往往不是“怎么写”,而是“什么时候不该用 await”“哪个 Promise 其实没被处理”。