Promise 对象
Promise 是 JavaScript 中处理异步操作的重要对象。它代表了一个异步操作的最终完成(或失败)及其结果值。Promise 提供了一种更优雅的方式来处理异步代码,避免了回调地狱的问题。
什么是 Promise?
Promise 是一个代表异步操作最终完成或失败的对象。它有三种状态:
- Pending(待定):初始状态,既没有被兑现,也没有被拒绝
- Fulfilled(已兑现):意味着操作成功完成
- Rejected(已拒绝):意味着操作失败
创建 Promise
使用 Promise 构造函数可以创建一个新的 Promise 对象:
javascript
// 创建一个 Promise
let myPromise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
let success = true;
if (success) {
resolve("操作成功!");
} else {
reject("操作失败!");
}
}, 1000);
});
// 使用 Promise
myPromise
.then(result => {
console.log(result); // "操作成功!"
})
.catch(error => {
console.error(error); // "操作失败!"
});Promise 方法
then 方法
then 方法用于处理 Promise 成功兑现的情况:
javascript
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("成功!"), 1000);
});
promise.then(
result => {
console.log(result); // "成功!"
// 可以返回新的值
return result.toUpperCase();
}
).then(
result => {
console.log(result); // "成功!"
}
);catch 方法
catch 方法用于处理 Promise 被拒绝的情况:
javascript
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("出错了!")), 1000);
});
promise
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error.message); // "出错了!"
});finally 方法
finally 方法无论 Promise 成功还是失败都会执行:
javascript
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("完成"), 1000);
});
promise
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
})
.finally(() => {
console.log("清理工作完成");
});Promise 静态方法
Promise.resolve()
返回一个以给定值解析的 Promise 对象:
javascript
let promise = Promise.resolve("成功");
promise.then(result => {
console.log(result); // "成功"
});Promise.reject()
返回一个带有拒绝原因的 Promise 对象:
javascript
let promise = Promise.reject(new Error("失败"));
promise.catch(error => {
console.error(error.message); // "失败"
});Promise.all()
等待所有 Promise 完成,如果任何一个被拒绝,则返回第一个拒绝的 Promise:
javascript
let promise1 = Promise.resolve(3);
let promise2 = 42;
let promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values); // [3, 42, "foo"]
});Promise.allSettled()
等待所有 Promise 完成,无论成功还是失败:
javascript
let promise1 = Promise.resolve(3);
let promise2 = Promise.reject("错误");
let promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.allSettled([promise1, promise2, promise3]).then((results) => {
console.log(results);
// [
// { status: 'fulfilled', value: 3 },
// { status: 'rejected', reason: '错误' },
// { status: 'fulfilled', value: 'foo' }
// ]
});Promise.race()
返回第一个完成的 Promise 的结果:
javascript
let promise1 = new Promise((resolve) => {
setTimeout(resolve, 500, '一个');
});
let promise2 = new Promise((resolve) => {
setTimeout(resolve, 100, '两个');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value); // "两个"
});链式调用
Promise 支持链式调用,可以依次处理多个异步操作:
javascript
function fetchUserData(userId) {
return fetch(`/api/users/${userId}`)
.then(response => response.json())
.then(user => {
console.log('获取用户信息:', user);
return user;
});
}
function fetchUserPosts(userId) {
return fetch(`/api/users/${userId}/posts`)
.then(response => response.json())
.then(posts => {
console.log('获取用户文章:', posts);
return posts;
});
}
// 链式调用
fetchUserData(123)
.then(user => {
return fetchUserPosts(user.id);
})
.then(posts => {
console.log('处理文章数据:', posts);
})
.catch(error => {
console.error('处理过程中出错:', error);
});错误处理
Promise 中的错误处理非常重要:
javascript
// 错误冒泡
new Promise((resolve, reject) => {
resolve("成功");
})
.then(result => {
throw new Error("处理过程中出错");
})
.then(result => {
console.log("这不会被执行");
})
.catch(error => {
console.error(error.message); // "处理过程中出错"
});
// 每个 Promise 都可以有自己的错误处理
new Promise((resolve, reject) => {
setTimeout(() => reject("失败"), 1000);
})
.catch(error => {
console.error("第一个错误处理:", error);
// 可以返回值继续链式调用
return "默认值";
})
.then(result => {
console.log("恢复后的结果:", result); // "默认值"
});实际应用示例
加载图片
javascript
function loadImage(src) {
return new Promise((resolve, reject) => {
let img = new Image();
img.onload = () => resolve(img);
img.onerror = () => reject(new Error(`图片加载失败: ${src}`));
img.src = src;
});
}
loadImage('path/to/image.jpg')
.then(img => {
document.body.appendChild(img);
console.log('图片加载成功');
})
.catch(error => {
console.error(error.message);
});并行处理多个请求
javascript
function fetchUserDetails(userId) {
return Promise.all([
fetch(`/api/users/${userId}`).then(r => r.json()),
fetch(`/api/users/${userId}/posts`).then(r => r.json()),
fetch(`/api/users/${userId}/comments`).then(r => r.json())
]).then(([user, posts, comments]) => {
return {
user,
posts,
comments
};
});
}
fetchUserDetails(123)
.then(data => {
console.log('用户详情:', data);
})
.catch(error => {
console.error('获取用户详情失败:', error);
});与 async/await 结合使用
Promise 与 async/await 结合使用可以让异步代码看起来像同步代码:
javascript
async function fetchUserData(userId) {
try {
let userResponse = await fetch(`/api/users/${userId}`);
let user = await userResponse.json();
let postsResponse = await fetch(`/api/users/${userId}/posts`);
let posts = await postsResponse.json();
return { user, posts };
} catch (error) {
console.error('获取数据失败:', error);
throw error;
}
}最佳实践
总是处理错误:使用
.catch()或 try/catch 处理 Promise 错误。避免嵌套 Promise:使用链式调用而不是嵌套。
javascript
// 不好的做法
promise.then(result => {
return anotherPromise(result).then(anotherResult => {
return yetAnotherPromise(anotherResult);
});
});
// 好的做法
promise
.then(result => anotherPromise(result))
.then(anotherResult => yetAnotherPromise(anotherResult));合理使用 Promise.all:当需要并行执行多个不相关的异步操作时使用。
避免在 Promise 构造函数中使用 Promise:这会导致不必要的嵌套。
javascript
// 不好的做法
new Promise((resolve, reject) => {
somePromise().then(resolve, reject);
});
// 好的做法
somePromise();- 使用 Promise.allSettled 处理部分失败:当希望即使部分 Promise 失败也要处理成功的 Promise 时使用。
Promise 是现代 JavaScript 异步编程的核心概念,掌握它对于编写高质量的异步代码至关重要。