Skip to content

十一、Promise 异步编程

Promise 是 ES6 引入的一种处理异步操作的新方式,它可以避免回调地狱,使异步代码更加清晰易读。

回调地狱是什么?

在 ES6 之前,处理异步操作通常使用回调函数,但当多个异步操作嵌套时,会形成回调地狱:

javascript
// 回调地狱示例
fs.readFile('file1.txt', 'utf8', function(err, data1) {
  if (err) throw err;
  fs.readFile('file2.txt', 'utf8', function(err, data2) {
    if (err) throw err;
    fs.readFile('file3.txt', 'utf8', function(err, data3) {
      if (err) throw err;
      console.log(data1 + data2 + data3);
    });
  });
});

这种代码难以阅读和维护,Promise 的出现就是为了解决这个问题。

Promise 基本语法

创建 Promise

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

消费 Promise

javascript
promise
  .then(result => {
    console.log(result); // 操作成功
  })
  .catch(error => {
    console.log(error); // 操作失败
  });

then() catch() finally()

then() 方法

then() 方法用于处理 Promise 成功的情况,它返回一个新的 Promise,所以可以链式调用。

javascript
const promise = new Promise((resolve, reject) => {
  resolve(1);
});

promise
  .then(value => {
    console.log(value); // 1
    return value * 2;
  })
  .then(value => {
    console.log(value); // 2
    return value * 2;
  })
  .then(value => {
    console.log(value); // 4
  });

catch() 方法

catch() 方法用于处理 Promise 失败的情况。

javascript
const promise = new Promise((resolve, reject) => {
  reject('出错了');
});

promise
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.log(error); // 出错了
  });

finally() 方法

finally() 方法无论 Promise 成功还是失败都会执行。

javascript
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功');
  }, 1000);
});

promise
  .then(result => {
    console.log(result); // 成功
  })
  .catch(error => {
    console.log(error);
  })
  .finally(() => {
    console.log('操作完成'); // 无论成功失败都会执行
  });

Promise.all() 并发请求

Promise.all() 方法接收一个 Promise 数组,只有当所有 Promise 都成功时才会成功,否则失败。

javascript
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('第一个请求成功'), 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('第二个请求成功'), 2000);
});

const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('第三个请求成功'), 1500);
});

Promise.all([promise1, promise2, promise3])
  .then(results => {
    console.log(results); // ['第一个请求成功', '第二个请求成功', '第三个请求成功']
  })
  .catch(error => {
    console.log(error);
  });

Promise.race()

Promise.race() 方法接收一个 Promise 数组,只要有一个 Promise 完成(成功或失败),就会返回那个 Promise 的结果。

javascript
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('第一个请求成功'), 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => resolve('第二个请求成功'), 500);
});

Promise.race([promise1, promise2])
  .then(result => {
    console.log(result); // 第二个请求成功(因为它更快)
  });

实战:模拟接口请求

javascript
// 模拟 API 请求
function fetchData(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(`Fetching data from ${url}`);
      resolve(`Data from ${url}`);
    }, 1000);
  });
}

// 顺序请求
fetchData('https://api.example.com/users')
  .then(data => {
    console.log(data);
    return fetchData('https://api.example.com/posts');
  })
  .then(data => {
    console.log(data);
    return fetchData('https://api.example.com/comments');
  })
  .then(data => {
    console.log(data);
    console.log('All requests completed');
  });

// 并发请求
Promise.all([
  fetchData('https://api.example.com/users'),
  fetchData('https://api.example.com/posts'),
  fetchData('https://api.example.com/comments')
])
  .then(results => {
    console.log(results);
    console.log('All requests completed');
  });

异步流程优雅写法

传统回调 vs Promise

javascript
// 传统回调
function getData(callback) {
  setTimeout(() => {
    callback('数据');
  }, 1000);
}

getData(data => {
  console.log(data);
});

// Promise
function getData() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('数据');
    }, 1000);
  });
}

getData().then(data => {
  console.log(data);
});

多个异步操作

javascript
// 传统回调
function step1(callback) {
  setTimeout(() => {
    callback('步骤1完成');
  }, 1000);
}

function step2(data, callback) {
  setTimeout(() => {
    callback(`${data}, 步骤2完成`);
  }, 1000);
}

function step3(data, callback) {
  setTimeout(() => {
    callback(`${data}, 步骤3完成`);
  }, 1000);
}

step1(data1 => {
  step2(data1, data2 => {
    step3(data2, data3 => {
      console.log(data3); // 步骤1完成, 步骤2完成, 步骤3完成
    });
  });
});

// Promise
function step1() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('步骤1完成');
    }, 1000);
  });
}

function step2(data) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(`${data}, 步骤2完成`);
    }, 1000);
  });
}

function step3(data) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(`${data}, 步骤3完成`);
    }, 1000);
  });
}

step1()
  .then(step2)
  .then(step3)
  .then(data => {
    console.log(data); // 步骤1完成, 步骤2完成, 步骤3完成
  });

Promise 的优势

  1. 避免回调地狱:使异步代码更加清晰易读
  2. 链式调用:可以方便地处理多个异步操作
  3. 错误处理:统一的错误处理机制
  4. 并发处理:支持多个异步操作的并发执行
  5. 与 async/await 配合:为 async/await 提供基础

通过本章节的学习,你已经掌握了 Promise 的基本用法和优势。Promise 是 ES6 中处理异步操作的重要特性,它使异步代码更加优雅和可维护。

© 2026 编程马·菜鸟教程 版权所有