文章中英模式
布鲁斯前端JS面试题目 - Promise、Async/Await 深入解析
深入讲解 JavaScript 中 Promise、Async/Await 的运作原理、使用方式、常见方法及实现,帮助你轻松应对面试中的相关问题。
文章中英模式
懒得看文章?那就来看视频吧
Promise 基本概念
Promise 是 JavaScript 中处理异步操作的标准方式,代表一个尚未完成但未来会完成的操作。Promise 有三种状态:
- •
Pending(等待中)
:初始状态,既不是成功也不是失败 - •
Fulfilled(已实现)
:操作成功完成 - •
Rejected(已拒绝)
:操作失败
const promise = new Promise((resolve, reject) => {
// Asynchronous operation
if (/* success */) {
resolve(value); // state changes to fulfilled
} else {
reject(error); // state changes to rejected
}
});
为何需要 Promise?
Promise 解决了传统回调函数的多个问题,提供了更优雅的异步处理方式:
- •
避免回调地狱
:解决嵌套回调导致的代码难以维护问题 - •
统一错误处理
:使用 catch 方法统一处理错误 - •
链式调用
:通过 then 方法实现清晰的流程控制 - •
更好的语义化
:Promise 的状态转换更符合程序设计直觉
// 传统回调方式
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log(finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
// Promise 方式
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => console.log(finalResult))
.catch(failureCallback);
Async/Await 的优势
Async/Await 是建立在 Promise 之上的语法糖,提供了更直观的方式来处理异步操作:
- •
同步风格
:使异步代码看起来像同步代码 - •
错误处理
:可以使用传统的 try/catch 处理错误 - •
调试方便
:可以像同步代码一样逐行调试 - •
条件处理
:更容易实现复杂的条件判断逻辑
async function fetchUserData() {
try {
const response = await fetch('/api/user');
const userData = await response.json();
return userData;
} catch (error) {
console.error('Error fetching user data:', error);
throw error;
}
}
Promise 的静态方法
Promise.all()
并行执行多个 Promise,等待全部完成。如果任一 Promise 失败,整个操作就失败。
Promise.all([
fetch('/api/users'),
fetch('/api/posts')
]).then(([users, posts]) => {
// process results
});
Promise.race()
返回最先完成的 Promise 结果,无论成功或失败。
Promise.race([
fetch('/api/data'),
new Promise((_, reject) =>
setTimeout(() => reject('Timeout'), 5000)
)
]);
Promise.any()
返回第一个成功的 Promise 结果,只有全部失败时才会拒绝。
Promise.any([
fetch('https://api1.example.com'),
fetch('https://api2.example.com')
]).then(firstSuccess => {
// Handle the first successful result
});
Promise.allSettled()
等待所有 Promise 完成,返回每个 Promise 的结果状态。
Promise.allSettled([
fetch('/api/users'),
fetch('/api/posts')
]).then(results => {
// process all results
});
🔥 常见面试题目
(一)Promise 的状态转换规则是什么?
解答:Promise 的状态转换有以下特点:
- •初始状态为 Pending(等待中)
- •只能从 Pending 转换到 Fulfilled(已实现)或 Rejected(已拒绝)
- •状态转换是不可逆的,一旦改变就不能再变化
- •状态转换时会触发对应的回调函数(then 或 catch)
(二)Promise.all 和 Promise.race 的区别?
解答:
特性 | Promise.all | Promise.race |
---|---|---|
完成条件 | 所有 Promise 都完成 | 任一 Promise 完成 |
失败处理 | 任一失败则整体失败 | 采用最先完成的结果 |
返回值 | 所有结果的数组 | 最先完成的结果 |
(三)async/await 和 Promise 的关系?
解答:
- •
async/await
是建立在 Promise 之上的语法糖 - •
async
函数总是返回一个 Promise - •
await
只能在 async 函数内使用 - •await 可以等待任何
"thenable"
对象(实现了 then 方法的对象)
// async 函数总是返回 Promise
async function example() {
return "Hello";
}
// 等同于
function example() {
return Promise.resolve("Hello");
}
// 验证 async 返回的是 Promise
console.log(example()); // Promise {<fulfilled>: "Hello"}
// await 解开的是 Promise resolve 的值
async function example() {
const result = await example(); // 等待 Promise.resolve("Hello") 的结果
console.log(result); // "Hello"
// 等同于
example().then(value => console.log(value)); // "Hello"
}
// 完整范例比较
// Promise 方式
function fetchData() {
return fetch('/api/data')
.then(response => response.json())
.then(data => data)
.catch(error => console.error(error));
}
// async/await 方式 - 更易读的同步风格
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data; // 自动被包装为 Promise.resolve(data)
} catch (error) {
console.error(error);
}
}
(四)如何实现自己的 Promise.all?
解答:我们可以实现一个简单的 MyPromise.all 函数,模拟 Promise.all 的功能:
function myPromiseAll(promises) {
return new Promise((resolve, reject) => {
// 如果传入的不是数组,直接拒绝
if (!Array.isArray(promises)) {
return reject(new TypeError('promises must be an array'));
}
const results = []; // 存储所有 promise 的结果
let completed = 0; // 已完成的 promise 数量
// 如果是空数组,直接返回空数组结果
if (promises.length === 0) {
return resolve(results);
}
// 遍历所有 promise
promises.forEach((promise, index) => {
// 使用 Promise.resolve 确保处理非 Promise 值
Promise.resolve(promise)
.then(result => {
results[index] = result; // 保持原始顺序
completed++;
// 当所有 promise 都完成时,解析最终结果
if (completed === promises.length) {
resolve(results);
}
})
.catch(error => {
// 任何一个 promise 拒绝,整个 myPromiseAll 就拒绝
reject(error);
});
});
});
}
// 使用范例
const p1 = Promise.resolve(1);
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 100));
const p3 = Promise.resolve(3);
myPromiseAll([p1, p2, p3])
.then(results => console.log(results)) // [1, 2, 3]
.catch(error => console.error(error));
这个实现的关键点:
- •返回一个新的
Promise
- •追踪所有
Promise
的完成状态 - •保持结果的原始顺序
- •任一
Promise
失败时立即拒绝整个Promise
- •使用
Promise.resolve
处理非 Promise 值