Skip to content

Promise 面试题

1. Promise 的基本概念

问题:什么是 Promise?它解决了什么问题?

答案: Promise 是异步编程的一种解决方案,用于表示一个异步操作的最终完成(或失败)及其结果值。

解决的问题

  • 回调地狱(Callback Hell)
  • 异步代码的可读性和可维护性
  • 错误处理的统一方式
  • 多个异步操作的并发执行

Promise 的三种状态

  • pending:初始状态,既未完成也未拒绝
  • fulfilled:操作成功完成
  • rejected:操作失败

2. Promise 的基本用法

问题:如何创建和使用 Promise?

答案

创建 Promise

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

使用 Promise

javascript
promise
  .then(result => {
    console.log(result); // '操作成功'
  })
  .catch(error => {
    console.error(error.message);
  })
  .finally(() => {
    console.log('操作完成');
  });

3. Promise 的链式调用

问题:Promise 的链式调用是如何工作的?

答案

链式调用原理

  • then()catch() 返回一个新的 Promise
  • 可以连续调用 then() 形成链式操作
  • 每个 then() 接收上一个 Promise 的结果

示例

javascript
fetchUser(1)
  .then(user => {
    console.log('用户:', user);
    return fetchOrders(user.id); // 返回新的 Promise
  })
  .then(orders => {
    console.log('订单:', orders);
    return fetchProducts(orders[0].id);
  })
  .then(product => {
    console.log('产品:', product);
  })
  .catch(error => {
    console.error('错误:', error);
  });

返回值规则

javascript
Promise.resolve(1)
  .then(value => {
    console.log(value); // 1
    return value * 2;   // 返回普通值
  })
  .then(value => {
    console.log(value); // 2
    return Promise.resolve(value * 2); // 返回 Promise
  })
  .then(value => {
    console.log(value); // 4
    // 不返回任何值
  })
  .then(value => {
    console.log(value); // undefined
  });

4. Promise 的静态方法

问题:Promise 有哪些静态方法?它们的作用是什么?

答案

Promise.resolve()

javascript
// 将值转换为 resolved 的 Promise
Promise.resolve('success');
Promise.resolve(Promise.resolve('value'));

Promise.reject()

javascript
// 创建 rejected 的 Promise
Promise.reject(new Error('失败'));

Promise.all()

javascript
// 等待所有 Promise 完成
const promises = [
  fetchUser(1),
  fetchUser(2),
  fetchUser(3)
];

Promise.all(promises)
  .then(users => {
    console.log('所有用户:', users);
  })
  .catch(error => {
    console.error('任一失败:', error);
  });

Promise.race()

javascript
// 返回最快完成的 Promise
const promises = [
  fetchFromCache(),
  fetchFromServer()
];

Promise.race(promises)
  .then(result => {
    console.log('最快的结果:', result);
  });

Promise.allSettled()

javascript
// 等待所有 Promise 完成,无论成功或失败
Promise.allSettled([
  Promise.resolve('success'),
  Promise.reject('error'),
  Promise.resolve('another success')
])
  .then(results => {
    console.log(results);
    // [
    //   { status: 'fulfilled', value: 'success' },
    //   { status: 'rejected', reason: 'error' },
    //   { status: 'fulfilled', value: 'another success' }
    // ]
  });

Promise.any()

javascript
// 返回第一个成功的 Promise
Promise.any([
  Promise.reject('error 1'),
  Promise.resolve('success'),
  Promise.reject('error 2')
])
  .then(result => {
    console.log('第一个成功:', result); // 'success'
  })
  .catch(error => {
    // 所有都失败时
    console.log(error.errors); // ['error 1', 'error 2']
  });

5. Promise 的错误处理

问题:Promise 中如何处理错误?

答案

错误处理方式

  1. catch() 方法
javascript
fetchData()
  .then(data => processData(data))
  .catch(error => {
    console.error('处理错误:', error);
  });
  1. then() 的第二个参数
javascript
fetchData()
  .then(
    data => console.log(data),
    error => console.error(error)
  );
  1. 全局错误处理
javascript
process.on('unhandledRejection', (reason, promise) => {
  console.error('未处理的 Promise 拒绝:', reason);
});

错误传播

javascript
Promise.resolve()
  .then(() => {
    throw new Error('第一步错误');
  })
  .then(() => {
    // 不会执行
  })
  .catch(error => {
    console.log(error.message); // '第一步错误'
    throw new Error('catch 中的错误');
  })
  .catch(error => {
    console.log(error.message); // 'catch 中的错误'
  });

6. async/await 与 Promise

问题:async/await 和 Promise 有什么关系?

答案

关系

  • async/await 是 Promise 的语法糖
  • async 函数返回 Promise
  • await 等待 Promise 完成

对比

javascript
// Promise 写法
function fetchUserData(userId) {
  return fetchUser(userId)
    .then(user => fetchOrders(user.id))
    .then(orders => ({ user, orders }));
}

// async/await 写法
async function fetchUserData(userId) {
  const user = await fetchUser(userId);
  const orders = await fetchOrders(user.id);
  return { user, orders };
}

错误处理对比

javascript
// Promise
fetchData()
  .then(data => console.log(data))
  .catch(error => console.error(error));

// async/await
try {
  const data = await fetchData();
  console.log(data);
} catch (error) {
  console.error(error);
}

7. Promise 的执行顺序

问题:以下代码的输出顺序是什么?

javascript
console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve().then(() => console.log('3'));

console.log('4');

答案: 输出顺序:1 → 4 → 3 → 2

原因

  1. 同步代码首先执行:1、4
  2. 微任务(Promise)在同步代码后执行:3
  3. 宏任务(setTimeout)最后执行:2

执行顺序规则

  • 同步代码
  • 微任务(Promise、process.nextTick)
  • 宏任务(setTimeout、setInterval、I/O)

8. Promise 的并发控制

问题:如何控制 Promise 的并发执行?

答案

限制并发数

javascript
async function asyncPool(poolLimit, array, iteratorFn) {
  const ret = [];
  const executing = [];
  
  for (const item of array) {
    const p = Promise.resolve().then(() => iteratorFn(item));
    ret.push(p);
    
    if (poolLimit <= array.length) {
      const e = p.then(() => executing.splice(executing.indexOf(e), 1));
      executing.push(e);
      if (executing.length >= poolLimit) {
        await Promise.race(executing);
      }
    }
  }
  
  return Promise.all(ret);
}

// 使用
const urls = ['url1', 'url2', 'url3', 'url4', 'url5'];
asyncPool(2, urls, fetchData);

顺序执行

javascript
async function runSequentially(tasks) {
  const results = [];
  for (const task of tasks) {
    const result = await task();
    results.push(result);
  }
  return results;
}

9. Promise 的取消

问题:如何取消一个 Promise?

答案

Promise 标准不支持取消,但可以通过包装实现:

javascript
function makeCancelable(promise) {
  let isCanceled = false;
  
  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then(
      value => isCanceled ? reject({ isCanceled: true }) : resolve(value),
      error => isCanceled ? reject({ isCanceled: true }) : reject(error)
    );
  });
  
  return {
    promise: wrappedPromise,
    cancel() {
      isCanceled = true;
    }
  };
}

// 使用
const { promise, cancel } = makeCancelable(fetchData());

promise
  .then(data => console.log(data))
  .catch(error => {
    if (error.isCanceled) {
      console.log('Promise 被取消');
    }
  });

// 取消
cancel();

10. Promise 的最佳实践

问题:使用 Promise 有哪些最佳实践?

答案

  1. 始终返回 Promise
javascript
// 好
function getData() {
  return fetchData().then(data => process(data));
}

// 不好
function getData() {
  fetchData().then(data => process(data)); // 没有返回
}
  1. 使用 catch 处理错误
javascript
fetchData()
  .then(data => process(data))
  .catch(error => handleError(error));
  1. 避免嵌套 Promise
javascript
// 不好
fetchData().then(data => {
  return fetchMoreData(data).then(moreData => {
    return process(moreData);
  });
});

// 好
fetchData()
  .then(data => fetchMoreData(data))
  .then(moreData => process(moreData));
  1. 使用 Promise.all 并行执行
javascript
// 顺序执行(慢)
const user = await fetchUser();
const orders = await fetchOrders();

// 并行执行(快)
const [user, orders] = await Promise.all([
  fetchUser(),
  fetchOrders()
]);
  1. 使用 async/await 提高可读性
javascript
async function getUserData(userId) {
  try {
    const user = await fetchUser(userId);
    const orders = await fetchOrders(user.id);
    return { user, orders };
  } catch (error) {
    console.error('获取用户数据失败:', error);
    throw error;
  }
}