Promise 的基本概念
Promise 是一个表示异步操作最终结果的对象,可能的结果有 成功(resolved) 或 失败(rejected)。Promise 主要用于处理异步操作的结果,并允许你在操作完成后进行相应的处理。
一个 Promise 对象有 三种状态:
- Pending(等待中): 初始状态,表示异步操作还没有完成。
- Fulfilled(已完成): 异步操作成功完成,并返回结果。
- Rejected(已拒绝): 异步操作失败,并返回错误。
如何创建一个 Promise
// executor函数会在new的时候立即执行
const promise = new Promise((resolve, reject) => {
// 执行异步操作
const success = true; // 模拟操作成功或失败
if (success) {
resolve('成功的结果'); // 操作成功时,调用 resolve
} else {
reject('失败的原因'); // 操作失败时,调用 reject
}
});
在构造函数 new Promise() 中,传入的参数是一个 executor 函数,接收两个参数:
- resolve:当异步操作成功时调用。
- reject:当异步操作失败时调用。
executor 函数在 new Promise 时立即同步执行
resolve(value):
- 当异步操作成功时调用,它会将 Promise 的状态从
pending(等待中)转变为fulfilled(已完成),并返回操作的成功结果。 value是成功的结果,它会传递到后续链式调用的then()中- resolve 可以传递任何类型的值: 字符串、数字、对象、甚至另一个 Promise。
reject(reason)
- 当异步操作失败时调用,它会将 Promise 的状态从
pending(等待中)转变为rejected(已拒绝),并返回失败的原因或错误。 reason是失败的原因或错误信息,它会传递到后续链式调用的catch()或then()的第二个参数中。- reject 也可以传递任何类型的错误信息: 字符串、对象、错误对象等。
const promise = new Promise((resolve, reject) => {
const success = true;
if (success) {
resolve({ message: "操作成功", code: 200 }); // 传递一个对象
} else {
reject(new Error("操作失败")); // 传递一个 Error 对象
}
});
promise
.then(result => {
console.log(result.message); // 输出 "操作成功"
})
.catch(error => {
console.log(error.message); // 输出 "操作失败"
});
then() 和**catch()**
then() 方法
then() 用于处理 Promise 成功 的结果。当 Promise 变为 fulfilled(成功) 状态时,then() 中的回调函数会被执行。
promise.then(onFulfilled, onRejected);
onFulfilled:Promise 成功时执行的回调函数,接收 Promise 的成功结果(resolve(value)的值)。onRejected:Promise 失败时执行的回调函数,接收 Promise 的失败原因(reject(reason)的值)。
传参
如果你只传递一个回调函数给
then(),那么这个回调函数会默认处理 成功 的情况,也就是onFulfilled,而onRejected会被忽略。const promise = new Promise((resolve, reject) => { resolve("操作成功"); }); promise .then(result => { console.log(result); // 输出 "操作成功" });- 只传递了一个
then()的回调,表示我们只处理成功的情况。 - 如果 Promise 被拒绝(
reject),则不会执行任何回调,也不会有错误处理。
- 只传递了一个
如果同时传递两个回调函数
const promise = new Promise((resolve, reject) => { const success = true; if (success) { resolve("操作成功"); } else { reject("操作失败"); } }); promise .then( result => { console.log(result); // 成功时输出 "操作成功" }, error => { console.log(error); // 失败时输出 "操作失败" } );如果你只希望传递 失败 的回调函数(
onRejected),可以这样做:const promise = new Promise((resolve, reject) => { reject("操作失败"); }); promise .then(null, error => { console.log(error); // 输出 "操作失败" });- 这里我们只传递了失败的回调(
onRejected),因此只有 Promise 失败时才会执行error回调并打印"操作失败"。 - 如果 Promise 成功了,
onFulfilled会被忽略,什么也不会发生。
- 这里我们只传递了失败的回调(
返回值
then() 中的回调函数不仅可以处理结果,还可以返回一个值,这个值将成为下一个 then() 的输入。
更重要的是,如果 then() 返回的是一个新的 Promise,then() 会等待这个 Promise 完成后再继续执行链式调用。
返回普通值
new Promise((resolve, reject) => {
resolve(1);
})
.then(result => {
return result + 1; // 返回值 2
})
.then(result => {
console.log(result); // 输出 2
})
.catch(error => {
console.error(error);
});
- 第一个
then()返回result + 1,即返回了2,这个返回值会被传递到下一个then()中。 - 第二个
then()接收到返回值并打印。
返回 Promise
new Promise((resolve, reject) => {
resolve(1);
})
.then(result => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(result + 1), 1000);
});
})
.then(result => {
console.log(result); // 输出 2,等待内部的 Promise 完成
})
.catch(error => {
console.error(error);
});
- 第一个
then()返回了一个新的 Promise,这个 Promise 会在 1 秒后返回result + 1。 - 第二个
then()会等待上一个 Promise 完成后,接收到返回的2并打印。
catch()
catch() 用于处理 Promise 失败 的原因。它捕获在 then() 中抛出的异常或错误。
promise.catch(onRejected);
onRejected:当 Promise 被 rejected(失败) 时,执行的回调函数,接收失败的原因(reject(reason)的值)。catch()本质上是then(null, onRejected)的语法糖。
new Promise((resolve, reject) => {
resolve(1);
})
.then(result => {
return result + 1; // 返回值 2
})
.then(result => {
console.log(result); // 输出 2
})
.catch(error => {
console.error(error);
});
catch() 方法不仅用于捕获 Promise 内部的错误,还可以捕获前面 then() 中的错误。
如果任何 then() 或异步操作抛出错误,catch() 会接收到错误并进行处理。
new Promise((resolve, reject) => {
throw new Error("发生错误");
})
.then(result => {
console.log(result); // 不会执行
})
.catch(error => {
console.error(error.message); // 输出 "发生错误"
});
- 在 Promise 中抛出错误,
catch()会捕获到这个错误并打印其message。
Promise 链式调用
Promise 支持链式调用,意味着每一个 .then() 返回一个新的 Promise 对象,因此可以继续进行链式调用。
const p = new Promise((resolve) => resolve(1));
p.then(res => res + 1) // 返回 2
.then(res => res * 2) // 返回 4
.then(res => console.log(res)); // 输出 4
Promise 的静态方法
Promise.resolve()
Promise.resolve() 返回一个 已完成(fulfilled)的 Promise 对象。
Promise.resolve(1).then(result => console.log(result)); // 输出 1
Promise.reject()
Promise.reject() 返回一个 已拒绝(rejected)的 Promise 对象。
Promise.reject("错误").catch(error => console.log(error)); // 输出 "错误"
Promise.all()
Promise.all() 用来并行执行多个异步操作,它会返回一个新的 Promise,只有当 所有 Promise 都成功 时才会触发 then,如果有任何一个 Promise 失败,就会触发 catch。
Promise.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
]).then(results => {
console.log(results); // 输出 [1, 2, 3]
}).catch(error => {
console.error(error);
});
Promise.race()
Promise.race() 用于竞争多个异步操作,它会返回第一个完成的 Promise,无论它是成功还是失败。
Promise.race([
new Promise(resolve => setTimeout(resolve, 1000, 'A')),
new Promise(resolve => setTimeout(resolve, 500, 'B'))
]).then(result => {
console.log(result); // 输出 'B',因为它先完成
});
Promise.allSettled()
Promise.allSettled() 会等待所有 Promise 完成(不论成功或失败),并返回每个 Promise 的状态。
Promise.allSettled([
Promise.resolve(1),
Promise.reject('失败'),
Promise.resolve(3)
]).then(results => {
console.log(results);
// 输出
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: '失败' },
// { status: 'fulfilled', value: 3 }
// ]
});
Promise.any()
Promise.any() 会等待 第一个成功 的 Promise。如果所有 Promise 都失败,则返回一个错误。
Promise.any([
Promise.reject('失败1'),
Promise.resolve('成功'),
Promise.reject('失败2')
]).then(result => {
console.log(result); // 输出 '成功'
}).catch(error => {
console.log(error);
});
async/await 和 Promise
async 函数
async 是一个关键字,用来声明一个异步函数。任何使用 async 声明的函数,都会隐式地返回一个 Promise 对象。
如果函数返回一个非 Promise 值,async 会自动将其包装成一个已经解决(fulfilled)的 Promise。
async function fetchData() {
return "数据加载完成";
}
fetchData().then(result => {
console.log(result); // 输出 "数据加载完成"
});
fetchData是一个async函数,返回的"数据加载完成"会被自动包装成一个已解决(fulfilled)的Promise,并在.then()中处理。
await 关键字
await 只能在 async 函数内使用。
await 会暂停函数的执行,直到 Promise 执行完毕并返回结果。
await 表达式返回的是 Promise 的解析值(resolve 的值)。如果 Promise 被拒绝(reject),await 会抛出一个错误。
async function fetchData() {
const response = await new Promise(resolve => {
setTimeout(() => resolve("数据加载完成"), 1000); // 模拟异步操作
});
console.log(response); // 输出 "数据加载完成"
}
fetchData();
await会暂停执行,直到Promise返回"数据加载完成",然后继续执行console.log(response)打印结果。
错误处理
在 async/await 中,我们使用 try/catch 来捕获异常,这与同步代码中的错误处理方式相同。
async function fetchData() {
try {
const response = await new Promise((resolve, reject) => {
setTimeout(() => reject("发生错误"), 1000); // 模拟异步失败
});
console.log(response); // 不会执行
} catch (error) {
console.error("错误信息:", error); // 输出 "错误信息: 发生错误"
}
}
fetchData();
- 由于
Promise被reject,await会抛出一个错误,catch会捕获到这个错误并打印出来。
结合 async/await 和 Promise
// 模拟获取用户信息
function getUserInfo() {
return new Promise(resolve => {
setTimeout(() => resolve({ id: 1, name: "Tom" }), 1000);
});
}
// 模拟根据用户ID获取订单信息
function getUserOrder(userId) {
return new Promise(resolve => {
setTimeout(() => resolve({ userId, orderId: 123 }), 1000);
});
}
// 模拟根据订单ID获取订单详情
function getOrderDetails(orderId) {
return new Promise(resolve => {
setTimeout(() => resolve({ orderId, product: "Laptop", price: 1000 }), 1000);
});
}
// 使用 async/await 执行异步操作
async function fetchOrderDetails() {
try {
const userInfo = await getUserInfo();
console.log("用户信息:", userInfo);
const orderInfo = await getUserOrder(userInfo.id);
console.log("订单信息:", orderInfo);
const orderDetails = await getOrderDetails(orderInfo.orderId);
console.log("订单详情:", orderDetails);
} catch (error) {
console.error("发生错误:", error);
}
}
fetchOrderDetails();
getUserInfo、getUserOrder和getOrderDetails都是返回 Promise 的函数。- 在
fetchOrderDetails中,我们使用await来等待这些异步操作依次完成。 - 如果任何一个操作失败,
catch会捕获错误。
输出:
用户信息: { id: 1, name: 'Tom' }
订单信息: { userId: 1, orderId: 123 }
订单详情: { orderId: 123, product: 'Laptop', price: 1000 }
async/await 与 Promise.all
async function fetchData() {
try {
const [user, order] = await Promise.all([
getUserInfo(), // 获取用户信息
getUserOrder() // 获取用户订单信息
]);
console.log("用户信息:", user);
console.log("订单信息:", order);
} catch (error) {
console.error("发生错误:", error);
}
}
async function getUserInfo() {
return new Promise(resolve => {
setTimeout(() => resolve("用户信息加载完成"), 1000);
});
}
async function getUserOrder() {
return new Promise(resolve => {
setTimeout(() => resolve("订单信息加载完成"), 1000);
});
}
fetchData();
Promise.all可以并行执行多个异步操作,这样可以提高效率,因为两个异步操作是并行执行的,而不是一个接一个地执行。await会等待Promise.all完成,结果是[user, order],分别对应getUserInfo()和getUserOrder()的结果。
async/await 的执行顺序
async 函数中的代码执行顺序与同步代码类似,但由于有 await,函数中的某些部分会暂停,直到 Promise 处理完成。
- 执行
async函数。 - 遇到
await,会暂停执行并等待Promise完成。 - 一旦
Promise完成,await会返回Promise的结果,函数继续执行。
async function fetchData() {
console.log("开始");
const first = await new Promise(resolve => {
setTimeout(() => resolve("第一步完成"), 1000);
});
console.log(first);
const second = await new Promise(resolve => {
setTimeout(() => resolve("第二步完成"), 1000);
});
console.log(second);
console.log("结束");
}
fetchData();
await会暂停函数执行,等待每一步Promise完成后,继续执行下一个操作。第一步完成和第二步完成是依次输出的,因为它们是顺序执行的。输出:
开始 第一步完成 第二步完成 结束