程序员面试宝典

一站式面试准备平台

返回分类
JavaScript中级

JavaScript Promise 与 async/await 详解

深入理解 Promise 异步编程模型及 async/await 语法糖

2026-03-26
阅读时间: 11分钟

JavaScript Promise 与 async/await 详解

Promise 是现代 JavaScript 异步编程的基础,理解 Promise 对于掌握 JavaScript 异步处理至关重要。

Promise 的基本概念

什么是 Promise

Promise 是 ES6 引入的用于处理异步操作的对象,它代表一个异步操作的最终完成或失败及其结果值。

Promise 有三种状态:

  • Pending(待定):初始状态,既不是成功也不是失败
  • Fulfilled(已兑现):操作成功完成
  • Rejected(已拒绝):操作失败

一旦 Promise 状态改变(从 Pending 变为 Fulfilled 或 Rejected),就不可再变。

Promise 的基本用法

javascript
const promise = new Promise((resolve, reject) => {
    // 异步操作
    setTimeout(() => {
        const success = true;
        if (success) {
            resolve('操作成功!');
        } else {
            reject(new Error('操作失败!'));
        }
    }, 1000);
});

promise
    .then(result => console.log(result))
    .catch(error => console.error(error))
    .finally(() => console.log('操作完成'));

Promise 链式调用

Promise 的最大优势之一是支持链式调用,解决回调地狱问题。

then() 的返回值

javascript
fetch('/api/user')
    .then(response => response.json())  // 返回新的 Promise
    .then(user => fetch(`/api/posts/${user.id}`))
    .then(response => response.json())
    .then(posts => console.log(posts))
    .catch(error => console.error(error));

返回值的处理

javascript
// 返回值会被包装成 Promise
Promise.resolve(1)
    .then(x => x + 1)      // x = 1, 返回 2
    .then(x => {
        return new Promise(resolve => setTimeout(() => resolve(x + 1), 1000));
    })
    .then(x => console.log(x));  // 1秒后输出 3

async/await

async/await 是 Promise 的语法糖,使异步代码看起来像同步代码。

基本语法

javascript
async function fetchUser() {
    try {
        const response = await fetch('/api/user');
        const user = await response.json();
        return user;
    } catch (error) {
        console.error('获取用户失败:', error);
    }
}

async 函数的返回值

async 函数总是返回 Promise:

javascript
async function getNumber() {
    return 42;
}

getNumber().then(console.log); // 42

await 的使用规则

javascript
// await 只能在 async 函数内部使用
async function example() {
    // 正确:直接在 async 函数中使用
    const result = await someAsyncFunction();
    
    // 错误:不能在普通函数中使用
    // const result = await someAsyncFunction(); // SyntaxError
}

Promise 组合

Promise.all

并行执行多个 Promise,全部成功才成功:

javascript
const promise1 = fetch('/api/user/1');
const promise2 = fetch('/api/user/2');
const promise3 = fetch('/api/user/3');

const users = await Promise.all([promise1, promise2, promise3]);
// 三个请求并行发出,全部完成后结果才可用

Promise.allSettled

等待所有 Promise 完成,无论成功或失败:

javascript
const results = await Promise.allSettled([
    fetch('/api/1'),
    fetch('/api/2'),
    fetch('/api/3')
]);

results.forEach((result, index) => {
    if (result.status === 'fulfilled') {
        console.log(`请求${index}成功:`, result.value);
    } else {
        console.log(`请求${index}失败:`, result.reason);
    }
});

Promise.race

返回最先完成(无论成功或失败)的 Promise:

javascript
const timeout = new Promise((_, reject) => 
    setTimeout(() => reject(new Error('请求超时')), 5000)
);

const request = fetch('/api/slow-endpoint');

Promise.race([request, timeout])
    .then(result => console.log(result))
    .catch(error => console.error(error)); // 5秒后超时

Promise.any

返回最先成功的 Promise(忽略失败):

javascript
const request1 = fetch('/api/fast');
const request2 = fetch('/api/medium');
const request3 = fetch('/api/slow');

try {
    const result = await Promise.any([request1, request2, request3]);
    console.log('最先成功的请求:', result);
} catch (error) {
    console.error('所有请求都失败了:', error.errors);
}

常见面试问题

Q1: Promise.then() 和 async/await 的区别?

特性Promise.then()async/await
语法链式调用像同步代码
错误处理.catch()try...catch
调试困难(异步堆栈)更易调试
适用场景简单转换复杂逻辑

Q2: async/await 和 Promise 的性能比较?

async/await 是 Promise 的语法糖,不存在性能差异。两者底层都是 Promise 机制。

Q3: 如何实现一个 Promise 重试机制?

javascript
async function retry(fn, maxAttempts = 3, delay = 1000) {
    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
        try {
            return await fn();
        } catch (error) {
            if (attempt === maxAttempts) throw error;
            await new Promise(resolve => setTimeout(resolve, delay));
        }
    }
}

// 使用
const data = await retry(() => fetch('/api/data').then(r => r.json()));

Q4: Promise.resolve() 和 new Promise() 的区别?

javascript
// new Promise() 创建一个新的 Promise 实例
const p1 = new Promise((resolve) => resolve(1));

// Promise.resolve() 对已存在的 Promise 进行优化(不创建新实例)
const p2 = Promise.resolve(1);

console.log(p1 === p2); // false - 严格相等时不同
// 但值是相同的

Q5: 如何让 Promise 支持取消?

Promise 本身不支持取消,但可以使用 AbortController:

javascript
const controller = new AbortController();

fetch('/api/data', { signal: controller.signal })
    .then(response => response.json())
    .then(console.log)
    .catch(err => {
        if (err.name === 'AbortError') {
            console.log('请求已取消');
        }
    });

// 取消请求
controller.abort();

最佳实践

  1. 总是使用 async/await 或 Promise,避免回调地狱
  2. 正确处理错误,使用 try...catch 或 .catch()
  3. 避免不必要的 await,在可以并行时使用 Promise.all
  4. 使用 Promise.allSettled 而非 Promise.all 当需要所有结果时
  5. 避免在循环中使用 await,改用 Promise.all
javascript
// ❌ 错误:串行执行,效率低
for (const url of urls) {
    const data = await fetch(url);
}

// ✅ 正确:并行执行
const results = await Promise.all(urls.map(url => fetch(url)));

相关标签