Promise 是 JavaScript 中管理异步操作的原生状态容器,具有 pending、fulfilled、rejected 三种不可逆状态;需显式调用 resolve/reject,支持链式处理、错误捕获及 async/await 语法糖。

Promise 是 JavaScript 中用于管理异步操作的原生对象,它不是语法糖,也不是回调函数的替代品——它是异步流程的“状态容器”,代表一个尚未完成但未来会完成(或失败)的操作。
Promise 的三种状态和基本构造
Promise 实例创建后处于 pending 状态;之后只能变成 fulfilled(成功)或 rejected(失败),且不可逆。构造时必须传入一个执行器函数:new Promise((resolve, reject) => { ... })。
常见误区是直接在构造函数里写异步逻辑却不调用 resolve 或 reject,导致 Promise 永远卡在 pending,后续 .then() 和 .catch() 都不会触发。
- 必须确保异步任务结束后显式调用
resolve(value)或reject(reason) - 执行器函数是同步立即执行的,但内部可包含
setTimeout、fetch、XMLHttpRequest等异步操作 -
resolve传入Promise实例时会自动展开(即“扁平化”),避免嵌套 Promise
用 .then() 和 .catch() 链式处理结果
.then() 接收两个可选参数:onFulfilled 和 onRejected;.catch() 等价于 .then(null, onRejected)。链式调用的关键在于:每个 .then() 返回的是一个新 Promise,其状态由该次回调的返回值决定。
立即学习“Java免费学习笔记(深入)”;
容易踩的坑是误以为 .then() 内部的 return 会“跳出整个链”,其实它只是决定下一个环节的输入值。
- 如果
.then()回调返回普通值(如字符串、数字),下一个.then()的onFulfilled会收到该值 - 如果返回另一个
Promise,下一个.then()会等待它 settle 后再执行 - 如果回调抛出错误(
throw)或返回被 reject 的 Promise,控制权会跳转到最近的.catch()或.then(null, ...)
const p = new Promise(resolve => setTimeout(() => resolve(42), 100));
p.then(x => x * 2)
.then(y => { throw new Error('oops'); })
.catch(err => console.log(err.message)); // 输出: oops常见异步场景下的实际写法(fetch / 定时器 / 并发)
原生 fetch 已返回 Promise,但注意它只在网络错误时 reject,HTTP 状态码如 404、500 仍属于 fulfilled 状态,需手动检查 response.ok。
对于定时器、事件监听等传统回调 API,需要用 Promise 封装才能接入链式流程。
- 封装
setTimeout:const delay = ms => new Promise(r => setTimeout(r, ms)) - 并发多个请求用
Promise.all([p1, p2, p3]),任一 reject 整体就 reject;若要全响应,改用Promise.allSettled - 竞速场景(如接口降级)用
Promise.race([fastApi(), fallback()]),谁先 settle 就取谁的结果
function apiWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
return fetch(url, { signal: controller.signal })
.finally(() => clearTimeout(id));
}async/await 是语法糖,但改变了错误捕获方式
async 函数本质是返回 Promise 的函数,await 只能在其中使用。它让异步代码看起来像同步,但底层仍是 Promise 链。
关键差异在于错误处理:用 try/catch 捕获 await 表达式的 rejection,而传统 .then().catch() 是声明式错误传递,容易漏掉中间环节的异常。
-
await后面如果不是 Promise,会被自动包装成Promise.resolve(...) - 多个
await默认串行;想并发请先用Promise.all包装好再await -
await在循环中逐个等待很慢,别写for (x of arr) await doAsync(x),除非真需要串行
最常被忽略的一点:async 函数内部未被 try/catch 包裹的同步错误(比如 undefined.foo())也会被转为 rejected Promise,这点和普通函数不同。











