Promise 是为解决回调地狱设计的异步抽象,不执行异步操作而管理其生命周期;构造时需传入执行器函数,内含由引擎注入的 resolve/reject;then/catch 链式调用返回新 Promise,async/await 是其语法糖但错误处理更直观。

Promise 不是 回调函数 的语法糖,而是为解决“回调地狱”而设计的异步抽象——它本身不执行异步操作,只管理异步操作的生命周期和状态流转。
Promise 构造函数必须传入一个执行器函数
创建 Promise 时,new Promise() 的参数是一个立即执行的函数,它接收两个参数:resolve 和 reject。这两个函数由 JS 引擎注入,不是你定义的。
常见错误:漏写执行器、或把异步逻辑写在 new Promise() 外面导致状态无法控制:
const p = new Promise(); // ❌ 报错:需要函数参数 const p = new Promise(() => setTimeout(() => {}, 100)); // ❌ resolve/reject 没调用,Promise 永远 pending
正确写法示例:
立即学习“Java 免费学习笔记(深入)”;
const p = new Promise((resolve, reject) => {fetch('/api/data') .then(res => res.json()) .then(data => resolve(data)) .catch(err => reject(err)); });
- 执行器函数同步运行,但内部可启动 异步任务
-
resolve和reject只能触发一次,多次调用会被忽略 - 未捕获的
reject会触发全局unhandledrejection事件
then() 和 catch() 链式调用的本质是返回新 Promise
then() 总是返回一个新的 Promise,其状态取决于回调函数的返回值:
- 返回普通值 → 新 Promise 状态为
fulfilled,值为该返回值 - 返回另一个 Promise → 新 Promise 等待它结束,并继承其状态和值
- 抛出异常或返回
Promise.reject()→ 新 Promise 状态为rejected
这意味着你可以安全地链式处理数据流,但也要小心 隐式转换:
Promise.resolve(1) .then(x => x + 1) // ✅ 返回 2,下个 then 接收到 2 .then(x => Promise.resolve(x * 2)) // ✅ 返回 Promise{4} .then(x => {throw 'oops'}) // ❌ 下个 catch 才能捕获 .catch(err => console.log(err));
注意:catch() 是 then(null, onRejected) 的语法糖,它只能捕获前一个 Promise 的 rejection,不能跨过中间的 then() 中的同步错误(除非那个 then() 内部没处理异常)。
async/await 是 Promise 的语法糖,但错误处理方式不同
async 函数返回一个 Promise,await 后面的表达式必须是 Promise(或可转为 Promise 的值),它会暂停函数执行直到 Promise settle。
关键差异在于错误传播:
-
then().catch()中,错误需显式传递到链尾 -
try/catch包裹await能直接捕获 Promise rejection,更接近同步代码直觉
但要注意:没有 try/catch 的 await 会让 rejection 变成未处理异常:
async function bad() { const data = await fetch('/api').then(r => r.json()); // ❌ 如果 fetch 失败,这里不会 throw,但 .then 里没 catch } async function good() { try { const res = await fetch('/api'); if (!res.ok) throw new Error(HTTP ${res.status}); const data = await res.json(); return data;} catch (err) {console.error('请求失败:', err); } }
Promise.all() 和 Promise.race() 的陷阱
Promise.all() 在任一 Promise rejected 时就立即 reject,不等其余完成;Promise.race() 则以第一个 settle 的为准(fulfill 或 reject 都算)。
典型误用场景:
- 用
Promise.all([p1, p2, p3])发起多个请求,但其中某个失败导致全部失败 → 应改用Promise.allSettled()(ES2020+) - 用
Promise.race([fetch(), timeout()])做超时控制时,忘记timeout()必须是Promise.reject(),否则 race 可能返回成功结果掩盖真实错误
超时控制正确写法:
function timeout(ms) {return new Promise((_, reject) => {setTimeout(() => reject(new Error('timeout')), ms); }); } Promise.race([fetch('/api'), timeout(5000) ]).catch(err => {if (err.message === 'timeout') console.log('请求超时'); else console.log('网络错误', err); });
真正难的是组合多个异步逻辑时的状态协调——比如并发限制、重试策略、缓存穿透防护,这些没法靠单个 Promise API 解决,得靠封装或 工具 库(如 p-limit、p-retry)。Promise 提供的是基础契约,不是银弹。






























