“`markdown
JavaScript Promise 入门教程:从基础到实践
在现代 Web 开发中,异步操作无处不在。从网络请求(AJAX)、用户事件处理、定时器到文件读写,JavaScript 作为一门单线程语言,必须依赖高效的异步处理机制来避免界面冻结,提升用户体验。早期,回调函数(Callback)是处理异步的主要方式,但随着业务逻辑复杂度的增加,“回调地狱”(Callback Hell)问题日益凸显,代码可读性和可维护性急剧下降。Promise 的出现,正是为了解决这一痛点,为 JavaScript 异步编程提供了一种更优雅、更强大的解决方案。
本文将带你深入理解 JavaScript Promise,从最基础的概念讲起,逐步过渡到实际应用场景,并探讨其高级用法和最佳实践。
1. 为什么需要 Promise?回调地狱的困境
在理解 Promise 之前,我们先回顾一下传统回调函数在处理异步操作时可能遇到的问题。
假设我们需要执行一系列异步操作:
1. 获取用户信息。
2. 根据用户信息获取用户订单。
3. 根据订单信息获取商品详情。
使用回调函数,代码可能如下所示:
``javascript
获取用户 ${userId} 的信息…`);
function getUserInfo(userId, callback) {
setTimeout(() => {
console.log(
const userInfo = { id: userId, name: “张三” };
callback(null, userInfo); // 假设没有错误
}, 1000);
}
function getUserOrders(userInfo, callback) {
setTimeout(() => {
console.log(获取用户 ${userInfo.name} 的订单...
);
const orders = [{ orderId: “O001”, amount: 100 }, { orderId: “O002”, amount: 200 }];
callback(null, orders);
}, 1000);
}
function getOrderDetails(order, callback) {
setTimeout(() => {
console.log(获取订单 ${order.orderId} 的商品详情...
);
const details = { orderId: order.orderId, items: [“商品A”, “商品B”] };
callback(null, details);
}, 1000);
}
// 调用
getUserInfo(123, (err, userInfo) => {
if (err) {
console.error(“获取用户信息失败:”, err);
return;
}
console.log(“用户信息:”, userInfo);
getUserOrders(userInfo, (err, orders) => {
if (err) {
console.error(“获取用户订单失败:”, err);
return;
}
console.log(“用户订单:”, orders);
if (orders.length > 0) {
getOrderDetails(orders[0], (err, details) => {
if (err) {
console.error(“获取订单详情失败:”, err);
return;
}
console.log(“订单详情:”, details);
// 如果还有后续操作,会继续嵌套下去…
});
}
});
});
“`
这种层层嵌套的结构,就是所谓的“回调地狱”。它带来了几个主要问题:
* 可读性差:代码横向发展,难以理解业务流程。
* 可维护性差:修改其中一个环节或增加新环节都非常困难。
* 错误处理复杂:每个回调都需要单独处理错误,容易遗漏,且错误处理逻辑分散。
* 控制流混乱:难以追踪代码的执行顺序和条件分支。
Promise 的设计目标之一就是解决这些问题,提供一种更线性的、可组合的异步编程模型。
2. Promise 的核心概念
什么是 Promise?
Promise 是一个对象,它代表了一个异步操作的最终完成(或失败)及其结果值。简单来说,Promise 是一个“承诺”,它承诺在未来某个时刻会给你一个结果。这个结果可能是成功的(fulfilled/resolved),也可能是失败的(rejected)。
Promise 的三种状态:
一个 Promise 必然处于以下三种状态之一:
- Pending(进行中):初始状态,既不是成功,也不是失败状态。这是 Promise 创建后的默认状态,异步操作正在进行。
- Fulfilled(已成功)/ Resolved(已解决):意味着操作成功完成。当 Promise 状态变为 Fulfilled 时,会有一个“值”(value)与之关联,这个值是异步操作的结果。
- Rejected(已失败):意味着操作失败。当 Promise 状态变为 Rejected 时,会有一个“原因”(reason)与之关联,这个原因通常是一个 Error 对象,表示操作失败的原因。
Promise 的特点:
- 状态一旦改变,就不会再变:Promise 的状态只能从 Pending 变为 Fulfilled,或者从 Pending 变为 Rejected。一旦状态改变(settled),就固定了,不能再次改变。
- 链式操作:Promise 提供了
.then()
和.catch()
方法,可以方便地进行链式调用,使异步代码更具可读性。
3. 创建和使用 Promise
3.1 创建 Promise
我们可以使用 new Promise()
构造函数来创建一个 Promise 实例。构造函数接收一个函数作为参数,这个函数被称为“执行器”(executor)。执行器函数会立即执行,并接收两个参数:resolve
和 reject
。
resolve(value)
: 当异步操作成功时调用,将 Promise 的状态从 Pending 变为 Fulfilled,并将value
作为结果传递出去。reject(reason)
: 当异步操作失败时调用,将 Promise 的状态从 Pending 变为 Rejected,并将reason
(通常是一个 Error 对象) 作为失败原因传递出去。
javascript
function fetchData(url) {
return new Promise((resolve, reject) => {
console.log(`开始从 ${url} 获取数据...`);
setTimeout(() => { // 模拟异步网络请求
const success = Math.random() > 0.3; // 模拟成功或失败
if (success) {
const data = { message: `成功获取来自 ${url} 的数据` };
resolve(data); // 操作成功,调用 resolve
} else {
const error = new Error(`从 ${url} 获取数据失败`);
reject(error); // 操作失败,调用 reject
}
}, 1500);
});
}
在上面的例子中,fetchData
函数返回一个 Promise。这个 Promise 内部模拟了一个异步操作。1.5秒后,根据随机数的结果,它可能会调用 resolve
并传递成功的数据,或者调用 reject
并传递一个错误对象。
3.2 消费 Promise: .then()
, .catch()
, .finally()
创建了 Promise 之后,我们需要一种方式来处理它的最终结果(成功或失败)。这通过 Promise 实例的 .then()
, .catch()
, 和 .finally()
方法来实现。
.then(onFulfilled, onRejected)
.then()
方法是最常用的方法,它接收两个可选的函数作为参数:
* onFulfilled
: 当 Promise 状态变为 Fulfilled 时被调用,接收 Promise 的成功值作为参数。
* onRejected
: 当 Promise 状态变为 Rejected 时被调用,接收 Promise 的失败原因作为参数。
“`javascript
const myPromise = fetchData(“https://api.example.com/data”);
myPromise.then(
(data) => { // onFulfilled
console.log(“成功:”, data.message);
},
(error) => { // onRejected
console.error(“失败:”, error.message);
}
);
console.log(“Promise 已发起,等待结果…”);
“`
如果只关心成功的情况,可以只传递第一个参数:
myPromise.then(data => console.log("成功:", data.message));
如果只关心失败的情况,可以将第一个参数设为 null
或 undefined
:
myPromise.then(null, error => console.error("失败:", error.message));
.catch(onRejected)
.catch()
方法是 .then(null, onRejected)
的语法糖,专门用于捕获 Promise 链中发生的错误。它只接收一个参数:
* onRejected
: 当 Promise 状态变为 Rejected 时被调用。
javascript
myPromise
.then(data => {
console.log("成功:", data.message);
})
.catch(error => {
console.error("捕获到错误:", error.message);
});
使用 .catch()
通常比在 .then()
中提供第二个参数更清晰,尤其是在 Promise 链中。
.finally(onFinally)
.finally()
方法在 Promise 状态改变后(无论是 Fulfilled 还是 Rejected)都会执行。它接收一个回调函数 onFinally
,这个函数不接收任何参数。.finally()
通常用于执行一些清理工作,比如关闭加载动画、释放资源等,无论 Promise 成功还是失败,这些操作都需要执行。
javascript
myPromise
.then(data => {
console.log("成功:", data.message);
})
.catch(error => {
console.error("捕获到错误:", error.message);
})
.finally(() => {
console.log("Promise 处理完毕,执行清理操作。");
});
重要:.finally()
的回调函数不接收参数,并且它的返回值(除非是抛出错误或返回一个被拒绝的 Promise)不会影响 Promise 链的结果。如果 .finally()
返回了一个 Promise,那么主 Promise 链会等待这个新的 Promise 完成。
4. Promise 链式调用
Promise 最强大的特性之一是链式调用。.then()
和 .catch()
方法都会返回一个新的 Promise 对象(注意,不是原始的 Promise 对象!),这使得我们可以将多个异步操作串联起来。
“`javascript
function step1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(“步骤 1 完成”);
resolve(“结果来自步骤1”);
}, 500);
});
}
function step2(dataFromStep1) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(“步骤 2 开始,接收到:”, dataFromStep1);
if (Math.random() > 0.3) {
resolve(结果来自步骤2 (基于 ${dataFromStep1})
);
} else {
reject(new Error(“步骤 2 失败”));
}
}, 500);
});
}
function step3(dataFromStep2) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(“步骤 3 开始,接收到:”, dataFromStep2);
resolve(结果来自步骤3 (基于 ${dataFromStep2})
);
}, 500);
});
}
step1()
.then(result1 => {
console.log(“接收到 step1 的结果:”, result1);
return step2(result1); // 返回一个新的 Promise
})
.then(result2 => {
console.log(“接收到 step2 的结果:”, result2);
return step3(result2); // 返回一个新的 Promise
})
.then(result3 => {
console.log(“接收到 step3 的结果:”, result3);
console.log(“所有步骤成功完成!”);
})
.catch(error => {
console.error(“链中发生错误:”, error.message);
// 链中的任何一个 Promise 被 reject,都会跳到最近的 .catch()
})
.finally(() => {
console.log(“Promise 链执行完毕。”);
});
“`
链式调用的关键点:
-
.then()
返回新的 Promise:- 如果
onFulfilled
或onRejected
回调函数返回一个值,那么.then()
返回的 Promise 会立即以这个值 resolve。 - 如果回调函数返回一个新的 Promise,那么
.then()
返回的 Promise 会“接管”这个新的 Promise 的状态,即等待这个新的 Promise 完成后,才会根据其结果 resolve 或 reject。这就是实现异步操作串联的核心。 - 如果回调函数抛出一个错误,那么
.then()
返回的 Promise 会立即以这个错误 reject。
- 如果
-
错误传递:在 Promise 链中,如果任何一个 Promise 被 reject,并且没有被后续的
.then()
的onRejected
处理,那么这个 reject 状态会一直向下传递,直到被一个.catch()
捕获。这使得错误处理非常集中和方便。
使用 Promise 链重写本教程开头的回调地狱示例:
``javascript
获取用户 ${userId} 的信息…`);
function getUserInfoPromise(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(
const userInfo = { id: userId, name: “张三” };
resolve(userInfo);
// if (error) reject(error); // 实际场景中会有错误处理
}, 1000);
});
}
function getUserOrdersPromise(userInfo) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(获取用户 ${userInfo.name} 的订单...
);
const orders = [{ orderId: “O001”, amount: 100 }, { orderId: “O002”, amount: 200 }];
if (Math.random() > 0.1) { // 模拟可能成功
resolve(orders);
} else {
reject(new Error(获取用户 ${userInfo.name} 订单失败
));
}
}, 1000);
});
}
function getOrderDetailsPromise(order) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(获取订单 ${order.orderId} 的商品详情...
);
const details = { orderId: order.orderId, items: [“商品A”, “商品B”] };
resolve(details);
}, 1000);
});
}
getUserInfoPromise(123)
.then(userInfo => {
console.log(“用户信息:”, userInfo);
return getUserOrdersPromise(userInfo); // 返回 Promise
})
.then(orders => {
console.log(“用户订单:”, orders);
if (orders.length > 0) {
return getOrderDetailsPromise(orders[0]); // 返回 Promise
} else {
return Promise.resolve(“用户没有订单”); // 或者返回一个已解决的 Promise
// 或者: throw new Error(“用户没有订单,无法获取详情”); // 抛出错误会被 catch 捕获
}
})
.then(detailsOrMessage => {
console.log(“最终结果:”, detailsOrMessage);
})
.catch(error => {
console.error(“处理过程中发生错误:”, error.message);
})
.finally(() => {
console.log(“所有异步操作流程结束。”);
});
“`
可以看到,代码变成了线性的,可读性和可维护性大大提高。
5. Promise 静态方法
Promise 对象本身也提供了一些有用的静态方法,用于处理多个 Promise 或创建特定状态的 Promise。
5.1 Promise.resolve(value)
返回一个以给定值 value
解析后的 Promise 对象。
* 如果 value
是一个普通值,返回的 Promise 会立即 fulfilled。
* 如果 value
是一个 Promise,Promise.resolve()
会原样返回这个 Promise。
* 如果 value
是一个 thenable 对象(即拥有 .then
方法的对象),Promise.resolve()
会尝试将其转换为一个 Promise,并立即执行其 .then
方法。
“`javascript
const p1 = Promise.resolve(123);
p1.then(val => console.log(“Promise.resolve(123):”, val)); // 输出: Promise.resolve(123): 123
const p2 = Promise.resolve(fetchData(“https://api.example.com/quick”));
p2.then(data => console.log(“Promise.resolve(promise):”, data))
.catch(err => console.error(“Promise.resolve(promise) Error:”, err));
const thenable = {
then: function(resolve, reject) {
setTimeout(() => resolve(“来自 thenable 的值”), 100);
}
};
const p3 = Promise.resolve(thenable);
p3.then(val => console.log(“Promise.resolve(thenable):”, val)); // 输出: Promise.resolve(thenable): 来自 thenable 的值
“`
5.2 Promise.reject(reason)
返回一个以给定原因 reason
拒绝的 Promise 对象。reason
通常是一个 Error 对象。
javascript
const pError = Promise.reject(new Error("这是一个主动拒绝的 Promise"));
pError.catch(err => console.error("Promise.reject():", err.message)); // 输出: Promise.reject(): 这是一个主动拒绝的 Promise
5.3 Promise.all(iterable)
接收一个 Promise 对象的数组(或任何可迭代对象)作为参数,并返回一个新的 Promise。
* 当 iterable 中的所有 Promise 都成功 (fulfilled) 时:返回的 Promise 才会成功,并且其成功值是一个数组,包含了 iterable 中每个 Promise 的成功值,顺序与原始数组一致。
* 当 iterable 中有任何一个 Promise 失败 (rejected) 时:返回的 Promise 会立即失败,并且其失败原因就是第一个失败的 Promise 的原因。其他 Promise 的结果会被忽略。
这适用于需要等待多个互不依赖的异步操作都完成后再进行下一步的场景。
“`javascript
const promise1 = Promise.resolve(3);
const promise2 = 42; // 非 Promise 值会被 Promise.resolve() 包装
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, ‘foo’);
});
const promise4Error = new Promise((resolve, reject) => {
setTimeout(reject, 50, new Error(‘Promise.all 失败测试’));
});
Promise.all([promise1, promise2, promise3])
.then(values => {
console.log(“Promise.all 成功:”, values); // 输出: Promise.all 成功: [3, 42, “foo”]
})
.catch(error => {
console.error(“Promise.all 失败:”, error.message);
});
Promise.all([promise1, promise4Error, promise3]) // promise4Error 会先 reject
.then(values => {
console.log(“Promise.all 成功 (这个不会执行):”, values);
})
.catch(error => {
console.error(“Promise.all 失败 (因为promise4Error):”, error.message); // 输出: Promise.all 失败 (因为promise4Error): Promise.all 失败测试
});
“`
5.4 Promise.race(iterable)
接收一个 Promise 对象的数组(或任何可迭代对象)作为参数,并返回一个新的 Promise。
* 当 iterable 中的任何一个 Promise 率先成功或失败时:返回的 Promise 会立即以这个率先改变状态的 Promise 的结果(成功值或失败原因)来解决或拒绝。
这适用于你关心多个异步操作中哪一个最先完成的场景,比如设置超时。
“`javascript
const pFast = new Promise((resolve, reject) => {
setTimeout(resolve, 100, ‘快的 Promise’);
});
const pSlow = new Promise((resolve, reject) => {
setTimeout(resolve, 500, ‘慢的 Promise’);
});
const pErrorRace = new Promise((resolve, reject) => {
setTimeout(reject, 30, new Error(‘Promise.race 快速失败’));
});
Promise.race([pFast, pSlow])
.then(value => {
console.log(“Promise.race 结果 (pFast vs pSlow):”, value); // 输出: Promise.race 结果 (pFast vs pSlow): 快的 Promise
})
.catch(error => {
console.error(“Promise.race 错误:”, error.message);
});
Promise.race([pSlow, pErrorRace])
.then(value => {
console.log(“Promise.race 结果 (这个不会执行):”, value);
})
.catch(error => {
console.error(“Promise.race 错误 (因为 pErrorRace):”, error.message); // 输出: Promise.race 错误 (因为 pErrorRace): Promise.race 快速失败
});
// 使用 Promise.race 实现超时
function fetchDataWithTimeout(url, timeoutMs) {
const fetchPromise = fetchData(url); // fetchData 返回一个Promise
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error(请求超时 (${timeoutMs}ms)
)), timeoutMs);
});
return Promise.race([fetchPromise, timeoutPromise]);
}
fetchDataWithTimeout(“https://api.example.com/slowdata”, 500) // fetchData 模拟1500ms
.then(data => console.log(“超时测试成功:”, data))
.catch(error => console.error(“超时测试失败:”, error.message)); // 500ms后会输出: 超时测试失败: 请求超时 (500ms)
“`
5.5 Promise.allSettled(iterable)
(ES2020)
接收一个 Promise 对象的数组作为参数,并返回一个新的 Promise。
* 当 iterable 中的所有 Promise 都已经 settled(即无论是 fulfilled 还是 rejected)时:返回的 Promise 会成功。其成功值是一个数组,数组中的每个元素都是一个对象,描述了对应 Promise 的最终状态和结果/原因。
* 如果 Promise 成功,对象形式为 { status: 'fulfilled', value: result }
* 如果 Promise 失败,对象形式为 { status: 'rejected', reason: error }
与 Promise.all()
不同,Promise.allSettled()
会等待所有 Promise 完成,而不管它们是成功还是失败。这在你希望知道所有异步操作的结果,即使其中一些失败了,也很有用。
“`javascript
const promiseAllSettled1 = Promise.resolve(300);
const promiseAllSettled2 = new Promise((resolve, reject) => setTimeout(reject, 100, new Error(‘一个明确的失败’)));
const promiseAllSettled3 = 400; // 也会被包装
Promise.allSettled([promiseAllSettled1, promiseAllSettled2, promiseAllSettled3])
.then(results => {
console.log(“Promise.allSettled 结果:”);
results.forEach(result => {
if (result.status === ‘fulfilled’) {
console.log(Fulfilled: ${result.value}
);
} else {
console.log(Rejected: ${result.reason.message}
);
}
});
});
// 输出:
// Promise.allSettled 结果:
// Fulfilled: 300
// Rejected: 一个明确的失败
// Fulfilled: 400
“`
5.6 Promise.any(iterable)
(ES2021)
接收一个 Promise 对象的数组作为参数,并返回一个新的 Promise。
* 当 iterable 中的任何一个 Promise 成功 (fulfilled) 时:返回的 Promise 会立即以第一个成功的 Promise 的值来解决。
* 如果 iterable 中的所有 Promise 都失败 (rejected) 时:返回的 Promise 会以一个 AggregateError
对象来拒绝。AggregateError
对象的 errors
属性是一个数组,包含了所有 Promise 的失败原因。
与 Promise.race()
不同,Promise.any()
会忽略所有 rejected 的 Promise,直到找到第一个 fulfilled 的 Promise。如果所有都 rejected,它才会 reject。
“`javascript
const pAny1 = Promise.reject(new Error(‘Any 失败1’));
const pAny2 = new Promise(resolve => setTimeout(resolve, 100, ‘Any 成功 (快)’));
const pAny3 = new Promise(resolve => setTimeout(resolve, 50, ‘Any 成功 (更快)’));
Promise.any([pAny1, pAny2, pAny3])
.then(value => {
console.log(“Promise.any 成功:”, value); // 输出: Promise.any 成功: Any 成功 (更快)
})
.catch(error => { // 这个不会执行
console.error(“Promise.any 失败:”, error);
});
const pAnyRejectAll1 = Promise.reject(new Error(‘全部失败1’));
const pAnyRejectAll2 = Promise.reject(new Error(‘全部失败2’));
Promise.any([pAnyRejectAll1, pAnyRejectAll2])
.then(value => { // 这个不会执行
console.log(“Promise.any 成功:”, value);
})
.catch(aggregateError => {
console.error(“Promise.any 失败 (所有都失败了):”, aggregateError.message);
aggregateError.errors.forEach(err => console.log(- ${err.message}
));
});
// 输出:
// Promise.any 失败 (所有都失败了): All promises were rejected
// – 全部失败1
// – 全部失败2
“`
6. Promise 的错误处理最佳实践
-
始终在 Promise 链的末尾添加
.catch()
:这是捕获所有未处理的 rejection 的最可靠方法。
javascript
doSomething()
.then(doSomethingElse)
.then(doMore)
.catch(err => console.error("统一处理错误:", err)); -
理解错误传递:如果一个
.then()
中的回调抛出错误,或者返回一个 rejected Promise,这个错误会沿着链向下传递,直到被.catch()
或下一个.then()
的onRejected
处理。 -
在
.then()
中处理特定错误 (可选):有时你可能想在链的中间处理特定步骤的错误,并可能从中恢复,让链继续下去。
javascript
step1()
.then(result1 => {
return step2(result1)
.catch(errForStep2 => {
console.warn("步骤2发生错误,但尝试恢复:", errForStep2.message);
return "步骤2的默认恢复值"; // 返回一个值,让链继续
});
})
.then(result2OrDefault => {
return step3(result2OrDefault);
})
.catch(err => { // 捕获step1或step3的错误,或step2中未能恢复的错误
console.error("最终错误处理:", err);
});
如果在step2().catch()
中不返回任何值(即return undefined
),或者重新throw errForStep2
,则链条会继续以 rejected 状态向下传递。 -
区分业务错误和程序错误:
- 业务错误(如“用户不存在”、“密码错误”)有时可以被认为是“成功”的异步操作,但结果表明了一个特定的业务场景。这种情况下,Promise 可能会 resolve 一个带有错误码或特定结构的对象。
- 程序错误(如网络中断、代码bug)通常应该导致 Promise reject 一个 Error 对象。
-
避免在
new Promise
的 executor 中使用try...catch
来调用reject
:
Executor 函数中的同步错误会自动使 Promise reject。
“`javascript
// 不推荐 (除非 try…catch 是为了捕获异步回调中的错误并 reject)
new Promise((resolve, reject) => {
try {
const result = riskySynchronousOperation();
resolve(result);
} catch (e) {
reject(e); // executor 中同步抛出的错误会自动 reject Promise
}
});// 更好 (executor 中同步错误自动 reject)
new Promise((resolve, reject) => {
const result = riskySynchronousOperation(); // 如果这里抛错,Promise 自动 reject
resolve(result);
});// try…catch 在 executor 中主要用于捕获 异步回调 内部的错误,并手动 reject
new Promise((resolve, reject) => {
someAsyncApiWithCallbacks((err, data) => {
if (err) {
reject(err); // 手动 reject
} else {
resolve(data);
}
});
});
“`
7. Promise 与 Async/Await
ES2017 (ES8) 引入了 async
和 await
关键字,它们是构建在 Promise 之上的语法糖,使得异步代码看起来更像同步代码,从而进一步提高了可读性。
async
函数:声明一个异步函数,该函数隐式返回一个 Promise。await
操作符:用于等待一个 Promise 完成。它只能在async
函数内部使用。await
会暂停async
函数的执行,直到 Promise 解析(fulfilled 或 rejected)。如果 Promise fulfilled,await
返回 Promise 的结果;如果 Promise rejected,await
会抛出 Promise 的错误原因(可以被try...catch
捕获)。
``javascript
成功获取来自 ${url} 的数据 (async/await)
// 使用 Promise 的 fetchData 函数
function fetchDataAsync(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = Math.random() > 0.3;
if (success) {
resolve({ message:});
从 ${url} 获取数据失败 (async/await)`));
} else {
reject(new Error(
}
}, 1000);
});
}
async function processData() {
console.log(“Async: 开始处理数据…”);
try {
const data1 = await fetchDataAsync(“https://api.example.com/resource1”);
console.log(“Async: 第一个资源:”, data1.message);
const data2 = await fetchDataAsync("https://api.example.com/resource2");
console.log("Async: 第二个资源:", data2.message);
console.log("Async: 所有数据处理完成。");
return "最终处理结果"; // async 函数的返回值会成为 Promise 的 resolve 值
} catch (error) {
console.error("Async: 处理过程中发生错误:", error.message);
throw error; // 或者 return Promise.reject(error);
// 如果不 throw,外部 Promise 会 resolve 为 undefined
}
}
processData()
.then(finalResult => {
console.log(“Async 调用成功:”, finalResult);
})
.catch(error => {
console.error(“Async 调用失败:”, error.message);
});
“`
async/await
极大地简化了 Promise 的使用,尤其是在处理复杂的异步流程时。但请记住,async/await
只是 Promise 的语法糖,其底层仍然是 Promise。理解 Promise 的原理对于高效使用 async/await
至关重要。
8. 总结与展望
Promise 是 JavaScript 异步编程的基石。它通过提供一个标准化的对象来表示异步操作的未来结果,解决了回调地狱的问题,使得异步代码更易于编写、阅读和维护。
核心回顾:
* 状态:Pending, Fulfilled, Rejected。
* 创建:new Promise((resolve, reject) => { ... })
。
* 消费:.then(onFulfilled, onRejected)
, .catch(onRejected)
, .finally(onFinally)
。
* 链式调用:.then()
返回新 Promise,实现异步操作串联。
* 静态方法:Promise.resolve()
, Promise.reject()
, Promise.all()
, Promise.race()
, Promise.allSettled()
, Promise.any()
提供了强大的组合能力。
* 错误处理:通过 .catch()
和 onRejected
回调集中处理。
* Async/Await:基于 Promise 的语法糖,使异步代码更同步化。
掌握 Promise 是现代 JavaScript 开发者的必备技能。它不仅是理解许多现代库和框架(如 Fetch API、Axios、React、Vue 等)异步行为的关键,也是编写高质量、可维护的异步 JavaScript 代码的基础。
随着 JavaScript 的不断发展,异步编程模式也在持续进化。但 Promise 作为其核心概念之一,其重要性不言而喻。希望本教程能帮助你扎实地掌握 Promise,并在你的项目中灵活运用,编写出更优雅的异步代码。
“`