Promise 高频面试题
文章目录
- 前言
- ✅ 一、Promise 基础面试题
- **1. Promise 是什么?解决了什么问题?**
- **2. Promise 有哪几种状态?能否变更多次?**
- **3. 以下代码输出什么?**
- 🧠 二、进阶 Promise 面试题
- **4. then 和 catch 的区别?可以多次 then 吗?**
- **5. 如何实现 Promise 链式调用?**
- **6. finally 的执行时机?能获取返回值吗?**
- ⚠️ 三、经典面试陷阱题
- **7. 连续多次调用 resolve/reject 会怎样?**
- **8. 手写一个 delay 函数:**
- **9. 如何用 Promise 实现串行请求?**
- 🔧 四、手写 Promise 核心(可问架构岗)
- **10. 实现一个最简单的 Promise**
- ✅ 五、面试总结高频问法归纳
- **手写一个完整符合 Promise/A+ 规范的 Promise 实现**
- ✅ 一、代码结构概览
- ✅ 二、完整实现代码(含注释)
- ✅ 三、使用测试示例
- ✅ 四、重点回顾(面试可用)
- **逐步拆解这份手写 Promise 实现中各函数的调用流程**,**彻底掌握执行顺序、作用和内部关系**。
- 🧱 一、构造函数 `constructor(executor)`
- 作用:
- 执行流程图:
- 核心代码段:
- ⚙️ 二、resolve() 和 reject()
- 作用:
- 🔁 三、then(onFulfilled, onRejected)
- 作用:
- 核心流程:
- 🔍 四、核心:\_resolvePromise(promise2, x, resolve, reject)
- 作用:
- 关键场景:
- 🚨 五、catch(onRejected)
- 本质上是:
- 🔚 六、finally(callback)
- 特点:
- 🧪 七、静态方法 resolve / reject
- 🧠 总体流程图解(简化逻辑)
- ✅ 小结一句话(适合记忆与面试):
前言
Promise 高频面试题(含详细解析),涵盖基础概念、常见陷阱、进阶应用与源码机制,适合 Vue/React 前端工程师、Node 开发者、技术负责人面试使用:
✅ 一、Promise 基础面试题
1. Promise 是什么?解决了什么问题?
答:
Promise
是一种异步编程解决方案,代表一个未来才会完成或失败的操作结果。- 它避免了回调地狱(callback hell),使异步代码更可读、可维护。
2. Promise 有哪几种状态?能否变更多次?
答:
状态 | 含义 |
---|---|
pending | 初始状态,未完成 |
fulfilled | 已完成,调用 resolve() 切换 |
rejected | 已失败,调用 reject() 切换 |
- Promise 只能从 pending → fulfilled 或 rejected;
- 状态只能变更一次,之后不可逆。
3. 以下代码输出什么?
const p = new Promise((resolve, reject) => {console.log(1)resolve()console.log(2)
})p.then(() => console.log(3))console.log(4)
答:
输出顺序:
1
2
4
3
解释:
- Promise 构造器是同步执行的;
.then()
是异步的微任务,在主线程执行完后才执行。
🧠 二、进阶 Promise 面试题
4. then 和 catch 的区别?可以多次 then 吗?
答:
.then(onFulfilled, onRejected)
可处理成功或失败;.catch()
是.then(undefined, onRejected)
的语法糖;- Promise 可多次
.then()
,每次返回的是一个新的 Promise。
5. 如何实现 Promise 链式调用?
Promise.resolve().then(() => {console.log('A')return 'B'}).then(res => {console.log(res)return Promise.resolve('C')}).then(console.log)
输出:
A
B
C
每个
.then()
会返回一个新的 Promise,return 的值会作为下一个 then 的入参。
6. finally 的执行时机?能获取返回值吗?
Promise.resolve(100).finally(() => {console.log('finally')return 200}).then(res => {console.log('then', res)})
输出:
finally
then 100
finally()
不影响值传递,它不能修改链的结果。
⚠️ 三、经典面试陷阱题
7. 连续多次调用 resolve/reject 会怎样?
const p = new Promise((resolve, reject) => {resolve('first')resolve('second')reject('error')
})p.then(console.log).catch(console.error)
输出:
first
- 只有第一次调用有效,之后的
resolve
或reject
都被忽略。
8. 手写一个 delay 函数:
function delay(ms) {return new Promise(resolve => setTimeout(resolve, ms))
}delay(1000).then(() => console.log('1 秒后输出'))
9. 如何用 Promise 实现串行请求?
const urls = ['url1', 'url2', 'url3']// 串行执行 fetch
urls.reduce((prev, url) => {return prev.then(() => fetch(url).then(res => res.json()))
}, Promise.resolve())
🔧 四、手写 Promise 核心(可问架构岗)
10. 实现一个最简单的 Promise
class MyPromise {constructor(fn) {this._resolve = nullthis._reject = nullfn(this._resolveCallback.bind(this), this._rejectCallback.bind(this))}_resolveCallback(value) {if (this._resolve) this._resolve(value)}_rejectCallback(err) {if (this._reject) this._reject(err)}then(resolveFn) {this._resolve = resolveFnreturn this}catch(rejectFn) {this._reject = rejectFnreturn this}
}
✅ 五、面试总结高频问法归纳
面试问题 | 推荐回答重点 |
---|---|
Promise 的三种状态是什么?能变几次? | pending → fulfilled/rejected,只变一次 |
then 和 catch 的区别? | catch 是 then 的语法糖,处理错误 |
finally 有返回值吗? | 没有,不能影响链的传递 |
多次调用 resolve 有效吗? | 只有第一次有效 |
微任务与宏任务区别?Promise 属于哪种? | Promise 属于微任务,执行顺序在 DOM 之后 |
手写 delay、链式调用、串行执行? | 熟练掌握,体现编码能力与思维清晰度 |
手写一个完整符合 Promise/A+ 规范的 Promise 实现
支持:
.then()
链式调用- 状态变更不可逆
- 异步执行(模拟微任务)
- 支持嵌套 Promise 解析
- 支持
.catch()
、.finally()
✅ 一、代码结构概览
class MyPromise {// 构造函数constructor(executor) {}// then 方法then(onFulfilled, onRejected) {}// catch 方法catch(onRejected) {}// finally 方法finally(callback) {}// resolve/reject 静态方法static resolve(value) {}static reject(reason) {}// 内部私有工具_resolvePromise(promise, x, resolve, reject) {}
}
✅ 二、完整实现代码(含注释)
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'class MyPromise {constructor(executor) {this.status = PENDINGthis.value = undefinedthis.reason = undefinedthis.onFulfilledCallbacks = []this.onRejectedCallbacks = []const resolve = value => {if (this.status === PENDING) {this.status = FULFILLEDthis.value = value// 执行成功回调队列this.onFulfilledCallbacks.forEach(fn => fn())}}const reject = reason => {if (this.status === PENDING) {this.status = REJECTEDthis.reason = reason// 执行失败回调队列this.onRejectedCallbacks.forEach(fn => fn())}}try {executor(resolve, reject)} catch (err) {reject(err)}}then(onFulfilled, onRejected) {// 值穿透处理onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => valonRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }const promise2 = new MyPromise((resolve, reject) => {const execCallback = (callback, value, resolve, reject) => {queueMicrotask(() => {try {const x = callback(value)this._resolvePromise(promise2, x, resolve, reject)} catch (err) {reject(err)}})}if (this.status === FULFILLED) {execCallback(onFulfilled, this.value, resolve, reject)} else if (this.status === REJECTED) {execCallback(onRejected, this.reason, resolve, reject)} else {this.onFulfilledCallbacks.push(() => {execCallback(onFulfilled, this.value, resolve, reject)})this.onRejectedCallbacks.push(() => {execCallback(onRejected, this.reason, resolve, reject)})}})return promise2}/*** x的可能值* x 是个普通值(原始类型)x 是基于 Promises/A+ 规范 promise 对象x 是基于其他规范的 promise 对象x 就是 promise2 (x 与 promise2 指向同一对象)*/_resolvePromise(promise2, x, resolve, reject) {if (x === promise2) {return reject(new TypeError('循环引用'))}if (x && (typeof x === 'object' || typeof x === 'function')) {let called = falsetry {const then = x.thenif (typeof then === 'function') {then.call(x,y => {if (called) returncalled = truethis._resolvePromise(promise2, y, resolve, reject)},err => {if (called) returncalled = truereject(err)})} else {resolve(x)}} catch (err) {if (!called) reject(err)}} else {resolve(x)}}catch(onRejected) {return this.then(null, onRejected)}finally(callback) {return this.then(value => MyPromise.resolve(callback()).then(() => value),reason => MyPromise.resolve(callback()).then(() => { throw reason }))}static resolve(val) {if (val instanceof MyPromise) return valreturn new MyPromise(resolve => resolve(val))}static reject(reason) {return new MyPromise((_, reject) => reject(reason))}
}
✅ 三、使用测试示例
const p = new MyPromise((resolve, reject) => {setTimeout(() => {resolve('hello')}, 1000)
})p.then(res => {console.log('结果:', res)return '下一步'
}).then(res => {console.log('第二步:', res)
})
✅ 四、重点回顾(面试可用)
功能点 | 实现说明 |
---|---|
状态管理 | PENDING → FULFILLED / REJECTED |
回调队列 | onFulfilledCallbacks / onRejectedCallbacks |
异步执行 | 使用 queueMicrotask() 模拟微任务行为 |
then 链式调用 | 每次返回一个新 Promise,并延续结果 |
嵌套 Promise 解析 | _resolvePromise 递归处理 |
值穿透 | 非函数处理 fallback 行为 |
逐步拆解这份手写 Promise 实现中各函数的调用流程,彻底掌握执行顺序、作用和内部关系。
🧱 一、构造函数 constructor(executor)
作用:
- 初始化状态(
PENDING
) - 定义
resolve()
和reject()
函数 - 执行用户传入的
executor(resolve, reject)
执行流程图:
new MyPromise((resolve, reject) => {// 同步执行resolve('ok') // 或 reject('err')
})
核心代码段:
this.status = PENDING
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []// 包裹 try-catch 捕获执行器错误
try {executor(resolve, reject)
} catch (err) {reject(err)
}
⚙️ 二、resolve() 和 reject()
作用:
- 确保状态只变一次;
- 记录值或错误;
- 执行回调队列。
const resolve = value => {if (this.status === PENDING) {this.status = FULFILLEDthis.value = valuethis.onFulfilledCallbacks.forEach(fn => fn())}
}
const reject = reason => {if (this.status === PENDING) {this.status = REJECTEDthis.reason = reasonthis.onRejectedCallbacks.forEach(fn => fn())}
}
🔁 三、then(onFulfilled, onRejected)
作用:
- 注册回调函数;
- 返回新 Promise(用于链式调用);
- 保证执行异步化(使用
queueMicrotask()
); - 使用
_resolvePromise()
解析 return 值(支持返回嵌套 Promise)。
核心流程:
then(onFulfilled, onRejected) {const promise2 = new MyPromise((resolve, reject) => {if (当前状态是 fulfilled) {queueMicrotask(() => {try {const x = onFulfilled(this.value)_resolvePromise(promise2, x, resolve, reject)} catch (err) {reject(err)}})}else if (当前是 pending) {this.onFulfilledCallbacks.push(() => {queueMicrotask(...)})}})return promise2
}
🔍 四、核心:_resolvePromise(promise2, x, resolve, reject)
作用:
-
遵守 Promise/A+ 规范的返回值处理逻辑:
- 如果
x
是对象或函数,尝试取x.then
- 如果
x.then
是函数,递归调用 - 如果不是,就
resolve(x)
- 避免循环引用
- 如果
关键场景:
if (x === promise2) {reject(new TypeError('循环引用'))
}if (typeof x === 'object' || typeof x === 'function') {const then = x.thenif (typeof then === 'function') {then.call(x, y => {_resolvePromise(promise2, y, resolve, reject)}, reject)} else {resolve(x)}
}
🚨 五、catch(onRejected)
本质上是:
promise.catch(fn) === promise.then(null, fn)
catch(onRejected) {return this.then(undefined, onRejected)
}
🔚 六、finally(callback)
特点:
- 无论
resolve
还是reject
都会执行 - 不会影响后续链上的值
finally(cb) {return this.then(val => MyPromise.resolve(cb()).then(() => val),err => MyPromise.resolve(cb()).then(() => { throw err }))
}
🧪 七、静态方法 resolve / reject
static resolve(value) {if (value instanceof MyPromise) return valuereturn new MyPromise(resolve => resolve(value))
}static reject(reason) {return new MyPromise((_, reject) => reject(reason))
}
🧠 总体流程图解(简化逻辑)
User -> new MyPromise(executor)-> 构造函数立即执行,注册 resolve/rejectPromise.then(onFulfilled)-> 注册微任务,返回 promise2executor 中 resolve() 调用-> 状态变更 + 执行回调 -> queueMicrotask(onFulfilled)onFulfilled 返回值通过 _resolvePromise 解析-> 支持值 / Promise / thenable 递归处理
✅ 小结一句话(适合记忆与面试):
MyPromise 的核心是状态控制 + 回调队列 + 微任务调度 + 嵌套 Promise 解析,整个 then 链通过递归
_resolvePromise
串联,遵守 A+ 规范、保证异步、可链式。
扩展:
浅显易懂的实现Promise之resolvePromise篇,Promise大收官