Skip to main content

Promise

一、Promise 的核心概念与背景

定义:Promise 是一种处理异步操作的对象,代表一个异步操作的最终完成(或失败)及其结果值。
诞生背景

  • 回调地狱(Callback Hell):多层嵌套的回调函数导致代码可读性差、维护困难。
  • 异常处理混乱:异步操作的错误无法通过传统 try-catch 捕获。

Promise 的三大状态

  • pending:初始状态,既不是成功也不是失败。
  • fulfilled:操作成功完成。
  • rejected:操作失败。
    状态一旦改变(从 pending 到 fulfilled 或 rejected),就会被冻结,不可再变。

二、Promise 的基本用法

1. 创建 Promise

const promise = new Promise((resolve, reject) => {
// 异步操作(如网络请求、定时器)
setTimeout(() => {
const success = true;
if (success) {
resolve('操作成功'); // 传递成功结果
} else {
reject(new Error('操作失败')); // 传递失败原因
}
}, 1000);
});

2. 消费 Promise

promise
.then((value) => {
console.log(value); // 输出:操作成功
})
.catch((error) => {
console.error(error); // 捕获错误
})
.finally(() => {
console.log('无论成功失败都会执行');
});

3. Promise 链式调用

fetchData()
.then((data) => processData(data)) // 返回新 Promise
.then((processedData) => saveData(processedData))
.catch((error) => handleError(error)); // 统一错误处理

三、Promise 的高级特性

1. Promise 静态方法

  • Promise.all(iterable)
    并行执行多个 Promise,全部成功时返回结果数组,任一失败则立即失败。

    Promise.all([promise1, promise2])
    .then(([result1, result2]) => { /* 处理结果 */ })
    .catch((error) => { /* 处理任一错误 */ });
  • Promise.race(iterable)
    多个 Promise 竞争,第一个完成(无论成功或失败)的结果作为最终结果。

    // 实现请求超时控制
    Promise.race([fetchData(), timeout(5000)])
    .then((data) => { /* 处理数据 */ })
    .catch((error) => { /* 处理超时或请求错误 */ });
  • Promise.allSettled(iterable)
    等待所有 Promise 完成(无论成功或失败),返回包含每个结果状态的数组。

    Promise.allSettled([promise1, promise2])
    .then((results) => {
    results.forEach((result) => {
    if (result.status === 'fulfilled') {
    console.log(result.value);
    } else {
    console.error(result.reason);
    }
    });
    });

2. 错误处理最佳实践

  • 全局错误捕获

    window.addEventListener('unhandledrejection', (event) => {
    console.error('未捕获的 Promise 错误:', event.reason);
    event.preventDefault(); // 阻止默认行为(如控制台警告)
    });
  • 链式捕获 vs 单独捕获

    // 链式捕获:任何环节出错都会被最终 catch 捕获
    promise.then(a).then(b).catch(error => { /* 处理所有错误 */ });

    // 单独捕获:仅捕获当前 Promise 的错误
    promise.then(a).catch(errA).then(b).catch(errB);

四、Promise 与 async/await 的结合

async/await 是 Promise 的语法糖,使异步代码更像同步代码:

async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
} catch (error) {
console.error('请求失败:', error);
throw error; // 继续向上抛出错误
}
}

// 调用异步函数
fetchData()
.then((data) => processData(data))
.catch((error) => handleError(error));

五、Promise 的性能优化

  1. 避免不必要的串行执行

    // 错误:串行执行(等待第一个完成再执行第二个)
    const result1 = await fetchData1();
    const result2 = await fetchData2();

    // 正确:并行执行(提高效率)
    const [result1, result2] = await Promise.all([fetchData1(), fetchData2()]);
  2. 限制并发数量

    // 实现并发控制(如同时最多 3 个请求)
    function limitConcurrency(tasks, concurrency) {
    let running = 0;
    const results = [];

    return new Promise((resolve, reject) => {
    const runNext = async () => {
    if (tasks.length === 0) {
    if (running === 0) resolve(results);
    return;
    }

    running++;
    const task = tasks.shift();
    try {
    const result = await task();
    results.push(result);
    } catch (error) {
    reject(error);
    } finally {
    running--;
    runNext();
    }
    };

    // 启动初始并发任务
    for (let i = 0; i < Math.min(concurrency, tasks.length); i++) {
    runNext();
    }
    });
    }

六、Promise 的常见误区与陷阱

  1. 忘记返回 Promise

    // 错误:未返回 Promise,导致链式调用中断
    .then(() => {
    fetchData(); // 未返回
    })

    // 正确
    .then(() => fetchData())
  2. 空 catch 块掩盖错误

    // 错误:捕获错误后不处理
    .catch(() => {})

    // 正确:至少记录错误
    .catch((error) => {
    console.error('捕获到错误:', error);
    throw error; // 继续传播错误
    })
  3. 同步代码中的 Promise 未被捕获

    // 错误:同步代码中直接抛出的错误无法被 Promise 捕获
    const promise = new Promise((resolve, reject) => {
    throw new Error('同步错误'); // 立即抛出,未被 reject 包装
    });

    // 正确:使用 try-catch 包裹同步代码
    const promise = new Promise((resolve, reject) => {
    try {
    // 可能抛出错误的同步代码
    } catch (error) {
    reject(error);
    }
    });

七、总结:Promise 的核心价值

  1. 解决回调地狱:通过链式调用替代嵌套回调。
  2. 统一的错误处理:使用 catch 捕获整条链上的错误。
  3. 并行与竞争控制:通过 allrace 等方法高效处理多个异步操作。
  4. 与 async/await 无缝集成:提供更优雅的异步代码写法。

Promise 是现代 JavaScript 异步编程的基础,掌握其原理和最佳实践是编写高性能、可维护代码的关键。