【DeepSeek帮我准备前端面试100问】(课后题二)Promise面试题集锦

201 阅读3分钟

Promise 面试题集锦

以下是常见的 Promise 面试题及其解析,帮助你深入理解 Promise 的工作原理和使用场景。

基础概念题

1. Promise 的基本状态有哪些?

答案

  • pending(进行中)
  • fulfilled(已成功)
  • rejected(已失败)

2. Promise 的状态变化是怎样的?

答案

  • 只能从 pending 变为 fulfilled 或从 pending 变为 rejected
  • 状态一旦改变就不能再变

代码输出题

3. 下面代码的输出顺序是什么?

console.log('1');

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

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

console.log('4');

答案: 1 → 4 → 3 → 2

解析

  • 同步代码优先执行(1,4)
  • Promise 的 then 属于微任务(microtask),在当前事件循环末尾执行
  • setTimeout 属于宏任务(macrotask),在下一次事件循环执行

4. 下面代码的输出是什么?

const promise = new Promise((resolve, reject) => {
  console.log(1);
  resolve();
  console.log(2);
});

promise.then(() => {
  console.log(3);
});

console.log(4);

答案: 1 → 2 → 4 → 3

解析

  • Promise 构造函数是同步执行的
  • then 回调是异步的微任务

链式调用题

5. 下面代码的输出顺序是什么?

Promise.resolve()
  .then(() => {
    console.log('promise1');
    return Promise.resolve('promise2');
  })
  .then((res) => {
    console.log(res);
  });

Promise.resolve()
  .then(() => {
    console.log('promise3');
  })
  .then(() => {
    console.log('promise4');
  });

答案(可能因浏览器实现略有不同): promise1 → promise3 → promise4 → promise2

解析

  • 第一个 Promise 链的第一个 then 先执行
  • 第二个 Promise 链的第一个 then 接着执行
  • 由于 return Promise.resolve() 会创建一个新的微任务,所以 promise2 最后输出

错误处理题

6. 下面代码的输出是什么?

Promise.reject('error')
  .then(
    () => console.log('success'),
    (err) => console.log('fail1', err)
  )
  .catch((err) => console.log('fail2', err));

答案: fail1 error

解析

  • reject 被 then 的第二个参数捕获
  • 由于错误已经被处理,catch 不会执行

7. 下面代码的输出是什么?

Promise.resolve()
  .then(() => {
    throw new Error('error');
  })
  .then(
    () => console.log('success'),
    (err) => console.log('fail1', err)
  )
  .catch((err) => console.log('fail2', err));

答案: fail1 Error: error

解析

  • 第一个 then 抛出错误
  • 被第二个 then 的第二个参数捕获
  • catch 不会执行因为错误已被处理

综合应用题

8. 实现一个 Promise.retry 方法,当 promise 失败后会重试指定的次数

答案

Promise.retry = function (promiseFn, times = 3) {
  return new Promise(async (resolve, reject) => {
    while (times--) {
      try {
        const result = await promiseFn();
        resolve(result);
        break;
      } catch (err) {
        if (!times) reject(err);
      }
    }
  });
};

// 使用示例
function getData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5 ? resolve('success') : reject('error');
    }, 1000);
  });
}

Promise.retry(getData, 3)
  .then(console.log)
  .catch(console.error);

9. 实现一个限制并发数的 Promise 调度器

答案

class Scheduler {
  constructor(max) {
    this.max = max;
    this.count = 0;
    this.queue = [];
  }

  add(promiseCreator) {
    return new Promise((resolve) => {
      this.queue.push(() => promiseCreator().then(resolve));
      this.run();
    });
  }

  run() {
    if (this.count < this.max && this.queue.length) {
      this.count++;
      const task = this.queue.shift();
      task().finally(() => {
        this.count--;
        this.run();
      });
    }
  }
}

// 使用示例
const scheduler = new Scheduler(2);
const timeout = (time) => new Promise((r) => setTimeout(r, time));

const addTask = (time, order) => {
  scheduler.add(() => timeout(time)).then(() => console.log(order));
};

addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');
// 输出:2 3 1 4

高级理解题

10. Promise 和 setTimeout 的执行顺序是怎样的?为什么?

答案

  • Promise 的回调属于微任务(microtask)
  • setTimeout 的回调属于宏任务(macrotask)
  • 事件循环中,微任务会在当前宏任务执行完后立即执行,而宏任务要等到下一次事件循环
  • 因此 Promise.then 总是比 setTimeout 先执行

11. 如何取消一个 Promise?

答案: 原生 Promise 无法直接取消,但可以通过以下方式实现类似效果:

  1. 使用 AbortController (较新浏览器支持)
const controller = new AbortController();
const signal = controller.signal;

const promise = new Promise((resolve, reject) => {
  signal.addEventListener('abort', () => {
    reject(new DOMException('Aborted', 'AbortError'));
  });
  // 正常异步操作
});

// 取消
controller.abort();
  1. 使用标志变量
let isCancelled = false;

const cancellablePromise = new Promise((resolve, reject) => {
  // 模拟异步操作
  setTimeout(() => {
    if (isCancelled) {
      reject(new Error('Cancelled'));
    } else {
      resolve('Success');
    }
  }, 1000);
});

// 取消
isCancelled = true;

这些题目涵盖了 Promise 的核心知识点,理解它们可以帮助你在面试中更好地应对相关问题。