/
Update
9 min read
中文 Promise
一、Promise 是什么?#
Promise 是 JavaScript 中处理异步操作的对象,代表一个尚未完成但预期将来会完成的操作 。它是回调函数的升级版,解决了”回调地狱”问题。
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
resolve('成功!'); // 将 Promise 状态变为 fulfilled
}, 1000);
});javascript二、为什么需要 Promise?#
回调地狱(Callback Hell)#
// ❌ 嵌套回调,代码横向发展,难以维护
getData(function(a) {
getMoreData(a, function(b) {
getMoreData(b, function(c) {
getMoreData(c, function(d) {
console.log(d);
});
});
});
});javascriptPromise 链式调用#
// ✅ 链式调用,代码纵向发展,清晰可读
getData()
.then(a => getMoreData(a))
.then(b => getMoreData(b))
.then(c => getMoreData(c))
.then(d => console.log(d))
.catch(err => console.error(err));javascript三、Promise 的三种状态#
Promise 对象有三种状态,状态一旦改变就不可再次改变 :
┌─────────────┐
│ pending │ ← 初始状态:进行中
│ (待定) │
└──────┬──────┘
│
┌─────────┴─────────┐
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ fulfilled │ │ rejected │
│ (已成功) │ │ (已失败) │
│ │ │ │
│ resolve() │ │ reject() │
│ 触发 │ │ 触发 │
└─────────────┘ └─────────────┘plaintext四、创建 Promise#
基础语法#
const promise = new Promise((resolve, reject) => {
// resolve: 异步操作成功时调用
// reject: 异步操作失败时调用
const success = true;
if (success) {
resolve('操作成功'); // 状态变为 fulfilled,传递结果
} else {
reject('操作失败'); // 状态变为 rejected,传递错误原因
}
});javascript实际示例:封装异步请求#
function fetchUser(userId) {
return new Promise((resolve, reject) => {
fetch(`https://api.example.com/users/${userId}`)
.then(response => {
if (!response.ok) {
reject(new Error('网络请求失败'));
}
return response.json();
})
.then(data => resolve(data))
.catch(error => reject(error));
});
}javascript五、消费 Promise:then / catch / finally#
.then() —— 处理成功#
promise
.then(value => {
console.log(value); // '操作成功'
return value + '!!!'; // 返回值传递给下一个 then
})
.then(value => {
console.log(value); // '操作成功!!!'
});javascriptthen 的两种回调:
promise.then(
onFulfilled, // 成功时执行(可选)
onRejected // 失败时执行(可选,但推荐用 catch)
);javascript.catch() —— 处理失败#
promise
.then(value => {
throw new Error('出错了');
})
.catch(error => {
console.error(error.message); // '出错了'
});javascript.finally() —— 无论成败都执行#
promise
.then(value => console.log(value))
.catch(error => console.error(error))
.finally(() => {
console.log('无论成功失败,都会执行');
// 常用于关闭加载动画、释放资源
});javascript六、Promise 的静态方法#
Promise.resolve() —— 快速创建成功 Promise#
Promise.resolve('立即成功').then(value => console.log(value));
// 等价于:
new Promise(resolve => resolve('立即成功'));javascriptPromise.reject() —— 快速创建失败 Promise#
Promise.reject('立即失败').catch(reason => console.error(reason));javascriptPromise.all() —— 全部成功才算成功#
const p1 = fetch('/api/user');
const p2 = fetch('/api/posts');
const p3 = fetch('/api/comments');
Promise.all([p1, p2, p3])
.then(([user, posts, comments]) => {
// 三个请求都成功,结果按顺序返回
console.log(user, posts, comments);
})
.catch(error => {
// 任意一个失败,立即进入 catch
console.error('至少一个请求失败:', error);
});javascript特点:并行执行,全部成功返回结果数组;一个失败立即失败。
Promise.race() —— 谁先完成用谁#
const fetchData = fetch('/api/data');
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('超时')), 5000)
);
Promise.race([fetchData, timeout])
.then(data => console.log(data))
.catch(err => console.error(err)); // 如果 5 秒内没拿到数据,显示超时javascript特点:返回最快完成的那个 Promise 的结果。
Promise.allSettled() —— 等待全部完成(无论成败)#
const promises = [
Promise.resolve('成功1'),
Promise.reject('失败'),
Promise.resolve('成功2')
];
Promise.allSettled(promises).then(results => {
console.log(results);
// [
// { status: 'fulfilled', value: '成功1' },
// { status: 'rejected', reason: '失败' },
// { status: 'fulfilled', value: '成功2' }
// ]
});javascript特点:等待所有 Promise 完成,返回每个 Promise 的状态和结果/原因。不会短路。
Promise.any() —— 任意一个成功#
Promise.any([
Promise.reject('失败1'),
Promise.resolve('成功!'),
Promise.resolve('也成功')
])
.then(value => console.log(value)) // '成功!'(第一个成功的)
.catch(error => console.error(error)); // 如果全部失败,进入 AggregateErrorjavascript特点:返回第一个成功的 Promise;如果全部失败,抛出 AggregateError。
七、async / await —— Promise 的语法糖#
async/await 让异步代码看起来像同步代码,本质上还是 Promise 。
基本用法#
async function getUser() {
try {
const response = await fetch('/api/user'); // 等待 Promise 完成
const user = await response.json(); // 等待下一个 Promise
console.log(user);
return user; // 自动包装为 Promise.resolve(user)
} catch (error) {
console.error('获取用户失败:', error);
throw error; // 自动包装为 Promise.reject(error)
}
}
// 调用
getUser().then(user => console.log(user));javascriptasync 函数总是返回 Promise#
async function foo() {
return 'hello'; // 等价于 Promise.resolve('hello')
}
async function bar() {
throw new Error('oops'); // 等价于 Promise.reject(new Error('oops'))
}javascriptawait 的注意事项#
// ✅ 并行执行(推荐)
const [user, posts] = await Promise.all([
fetchUser(),
fetchPosts()
]);
// ❌ 串行执行(慢)
const user = await fetchUser(); // 等 1 秒
const posts = await fetchPosts(); // 再等 1 秒,总共 2 秒javascript八、手写 Promise(面试常考)#
理解 Promise 的最佳方式是手写一个简化版:
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolve(x);
} catch (error) {
reject(error);
}
});
} else if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolve(x);
} catch (error) {
reject(error);
}
});
} else {
// pending 状态,存入回调队列
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolve(x);
} catch (error) {
reject(error);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolve(x);
} catch (error) {
reject(error);
}
});
});
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
// 使用
const p = new MyPromise((resolve, reject) => {
setTimeout(() => resolve('成功'), 1000);
});
p.then(value => console.log(value)); // 1 秒后输出 "成功"javascript九、常见面试题#
题目 1:输出顺序#
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');javascript答案:1 → 4 → 3 → 2
解析:同步代码(1、4)先执行;Promise.then 是微任务,优先于 setTimeout 宏任务。
题目 2:Promise 链#
Promise.resolve(1)
.then(x => x + 1) // 返回 2
.then(x => { throw new Error('oops') })
.catch(() => 3) // 捕获错误,返回 3
.then(x => x + 1) // 返回 4
.then(console.log); // 输出 4javascript答案:4
题目 3:async/await 与 Promise#
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(() => console.log('setTimeout'), 0);
async1();
new Promise(resolve => {
console.log('promise1');
resolve();
}).then(() => console.log('promise2'));
console.log('script end');javascript答案:script start → async1 start → async2 → promise1 → script end → async1 end → promise2 → setTimeout
十、最佳实践#
| 场景 | 推荐做法 |
|---|---|
| 处理异步错误 | 始终使用 .catch() 或 try/catch |
| 多个独立请求 | 使用 Promise.all() 并行 |
| 超时控制 | 使用 Promise.race() |
| 需要等待全部结果 | 使用 Promise.allSettled() |
| 链式调用 | 每个 .then() 返回新 Promise |
| 现代项目 | 优先使用 async/await |
| 循环中发请求 | 用 for...of + await 代替 forEach |
// ❌ forEach 不会等待
urls.forEach(async url => {
await fetch(url); // 并发执行,不等待
});
// ✅ for...of 会顺序等待
for (const url of urls) {
await fetch(url); // 顺序执行,等待每个完成
}javascriptPromise 是 JavaScript 异步编程的基石,掌握它之后,再配合事件循环的理解,就能彻底搞懂 JS 的异步机制。