Appearance
1️⃣ 什么是 Promise?
Promise 是 JavaScript 为了解决回调地狱(callback hell)问题而引入的一种异步编程解决方案。
ts
const promise = new Promise((resolve, reject) => {
// 异步操作
if (success) {
resolve(result);
} else {
reject(error);
}
});
resolve(value)
:代表成功,状态变为 fulfilled。reject(error)
:代表失败,状态变为 rejected。
Promise 有三种状态:
状态 | 含义 |
---|---|
pending | 等待中 |
fulfilled | 已成功 |
rejected | 已失败 |
2️⃣ Promise 的使用
基本链式调用
ts
promise
.then((res) => console.log(res))
.catch((err) => console.error(err))
.finally(() => console.log('done'));
.then()
:接收成功回调。.catch()
:接收失败回调。.finally()
:无论成功失败都会执行。
3️⃣ Promise 的特性
一旦状态改变,就不可再次更改(不可逆)。
then/catch 注册的是微任务。
多次
.then()
/.catch()
不会导致 Promise 重复执行。
4️⃣ async / await 是什么?
async
是用来声明一个异步函数,它会自动将返回值包装成Promise
。await
是用来等待一个 Promise 执行完成。
ts
async function getData() {
try {
const result = await fetch('/api/data');
console.log(result);
} catch (err) {
console.error(err);
}
}
等价形式:
ts
fetch('/api/data')
.then((res) => console.log(res))
.catch((err) => console.error(err));
5️⃣ async/await 的底层原理
✅ 本质上是 Promise + 语法糖
ts
async function foo() {
const res = await Promise.resolve('hello');
return res;
}
等价于:
ts
function foo() {
return Promise.resolve('hello');
}
await
会暂停当前函数的执行,等到 Promise 结果返回后再继续。await
后面可以跟普通值、Promise 或 async 函数。
6️⃣ await 的行为细节
如果
await
后是普通值,会自动包装成 Promise。如果是 Promise,会等待该 Promise resolve 后再继续执行。
await
后的表达式执行异常,相当于Promise.reject()
,需用try/catch
捕获。
ts
await 1; // 相当于 await Promise.resolve(1);
await Promise.reject('error'); // 抛出错误
ts
async function test() {
try {
const result = await Promise.reject('失败了');
console.log(result);
} catch (error) {
console.error('捕获到了错误:', error); // ✅ 正确捕获
}
}
- 附上一错误捕获工具函数
ts
async function withCatch<T>(promise: Promise<T>): Promise<[T | null, any]> {
try {
const result = await promise;
return [result, null];
} catch (err) {
return [null, err];
}
}
async function process() {
const [res1, err1] = await withCatch(step1());
if (err1) return console.error('step1 失败', err1);
const [res2, err2] = await withCatch(step2());
if (err2) return console.error('step2 失败', err2);
const [res3, err3] = await withCatch(step3());
if (err3) return console.error('step3 失败', err3);
}
7️⃣ async/await 和 Promise 的对比
特性 | Promise | async/await |
---|---|---|
可读性 | 回调链可能较长 | 代码更清晰,类似同步流程 |
错误处理 | .catch() 捕获 | try...catch 捕获 |
并发处理 | .all() , .race() | 可用 Promise.all() 搭配 await |
使用难度 | 略高 | 较低,适合结构化异步代码 |
8️⃣ 并发 & 串行执行技巧
并发(同时执行多个异步任务):
ts
await Promise.all([task1(), task2(), task3()]);
串行(一个一个顺序执行):
ts
await task1();
await task2();
await task3();
Promise.allSettled()说明
ts
Promise.allSettled(promises: Promise<any>[])
返回一个 Promise,当所有的 promises 都已 完成(不管成功或失败) 时,返回一个数组,数组中的每一项是:
- { status: "fulfilled", value: any } — 如果对应的 Promise 成功。
- { status: "rejected", reason: any } — 如果对应的 Promise 失败。
ts
const p1 = Promise.resolve('🍎 Apple');
const p2 = Promise.reject('🍌 Banana error');
const p3 = new Promise((resolve) => setTimeout(() => resolve('🍇 Grape'), 500));
Promise.allSettled([p1, p2, p3])
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`任务 ${index + 1} 成功:`, result.value);
} else {
console.log(`任务 ${index + 1} 失败:`, result.reason);
}
});
});
任务 1 成功: 🍎 Apple
任务 2 失败: 🍌 Banana error
任务 3 成功: 🍇 Grape
🔍 和 Promise.all() 区别
方法 | 出错是否中断 | 返回内容 |
---|---|---|
Promise.all() | 是(第一个失败就中断) | 成功值数组或抛出错误 |
Promise.allSettled() | 否(全部都等) | 每个任务的状态与结果组成的数组 |
9️⃣ 实现简易版 Promise(简化版)
ts
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = null;
this.reason = null;
this.onResolved = [];
this.onRejected = [];
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolved.forEach(fn => fn());
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejected.forEach(fn => fn());
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
if (this.state === 'fulfilled') {
onFulfilled(this.value);
} else if (this.state === 'rejected') {
onRejected(this.reason);
} else {
this.onResolved.push(() => onFulfilled(this.value));
this.onRejected.push(() => onRejected(this.reason));
}
}
}
🔟 常见面试题分析
❓ Promise 为什么只执行一次?
ts
const p = new Promise(resolve => {
console.log('start');
resolve();
});
p.then(() => console.log('then1'));
p.then(() => console.log('then2'));
✅ 输出:
start
then1
then2
解释:Promise 执行器立即执行,then
不会触发多次执行,而是订阅回调。
❓ async/await 为何只输出一次“开始”?
ts
const a = new Promise(resolve =>
setTimeout(() => {
console.log('开始');
resolve('done');
}, 1000)
);
async function b() {
await a;
console.log('结束b');
}
function c() {
a.then(() => {
console.log('结束c');
});
}
b();
c();
✅ 输出:
开始
结束c
结束b
✅ 原因:a
是同一个 Promise,只执行一次定时器。多次 await
或 .then()
不会重复触发执行器。
❓ 为什么下述代码 await 不生效
ts
const e = async () => {
await Promise.resolve(setTimeout(() => {
console.log('xx');
}, 1000))
console.log('xxxx');
}
setTimeout
本身 不是一个 Promise,它返回的是一个定时器 ID(数字),所以你 Promise.resolve(setTimeout(...))
实际上是:
ts
await Promise.resolve(42); // 假设返回的 timer id 是 42
正确写法
ts
await new Promise((resolve) => {
setTimeout(() => {
console.log('xx');
resolve();
}, 1000);
});
✅ 总结
内容 | 总结 |
---|---|
Promise | 用于异步操作,状态不可逆 |
async/await | 是基于 Promise 的语法糖,更符合同步编程习惯 |
await 原理 | 会暂停当前函数的执行,等待 Promise resolve 结果 |
多次 then | 不会重复执行 Promise,都会接收相同的结果 |
异常处理 | Promise 用 .catch() ,async/await 用 try/catch |
并发处理 | 使用 Promise.all 进行并发 |