JavaScript 手动实现 Promise 核心逻辑详解
本文详细解析如何使用 JavaScript 手动实现 Promise 核心功能。从构造函数、状态管理到 then 方法的链式调用,逐步讲解 resolve 与 reject 机制。涵盖 catch、finally 的特殊处理,以及 Promise.all 和 Promise.race 的底层逻辑,帮助开发者深入理解异步编程原理。
Promise 构造函数与状态管理
为了深入理解 Promise 的内部机制,我们将通过以下步骤逐步模拟实现其核心功能。
首先,需要创建一个构造函数,作为 Promise 实例的基础载体。
在构造函数中接收一个执行函数(executor),该函数接收两个参数:resolve 和 reject。构造函数内部会立即同步执行这个执行函数,而 resolve 或 reject 触发的回调则被安排为异步执行。
Promise 的状态一旦从 pending 变更为 fulfilled 或 rejected,便不可再更改。状态流转只能是 pending => fulfilled 或 pending => rejected。
then 方法实现与异常处理
在调用 then 方法时,必须处理传入参数的类型。successCallback 和 failCallback 可能并非函数,因此需要对此进行兼容处理。
对于默认的 failCallback,如果未提供,必须将异常重新抛出。这样做的目的是让异常能够冒泡,从而被后续的 Promise 链捕获。
在 then 中执行回调函数时,必须使用 try-catch 捕获可能出现的异常,并将这些异常传递给下一个 Promise,以确保错误处理的连贯性。
- 如果 Promise 的状态尚未变更(仍为 pending),则需要将当前的回调方法添加到对应的成功或失败队列中,等待状态变更时执行。
- 如果 Promise 的状态已经变更(fulfilled 或 rejected),则需要通过异步方式(如 setTimeout 或 microtask)来处理成功或失败的回调,以确保符合 Promise/A+ 规范中关于异步执行的约定。
- 采用异步处理的原因在于,回调函数的执行结果可能与当前 then 返回的 Promise 实例一致,直接同步执行可能导致死循环问题,异步执行可有效避免此风险。
catch 与 finally 的特殊处理
catch 方法本质上是 then 方法的一种语法糖,仅传入 reject 回调,旨在简化错误处理的代码编写和理解。
finally 方法具有独特的行为特征,无论 Promise 最终是 resolve 还是 reject,它都会执行。
- 无论 Promise 的状态如何变化,finally 中的回调函数都会被执行。
- finally 接收的回调函数不接收任何参数,因为它不关心 Promise 的最终结果值或错误原因。
- finally 方法返回一个新的 Promise,且其值可以穿透到后续的 then 或 catch 中。如果 finally 中抛出异常,新 Promise 将被 reject;否则,新 Promise 将沿用原 Promise 的状态和值。
静态方法:resolve 与 reject
Promise.resolve 和 Promise.reject 是静态方法,它们根据传入的参数直接返回一个对应状态(fulfilled 或 rejected)的 Promise 对象。
Promise.all 与 Promise.race 实现
Promise.all 方法用于处理多个 Promise 实例的并发执行,其核心特点如下。
- Promise.all 返回一个新的 Promise 对象。
- 当所有输入的 Promise 都成功(resolve)时,输出的 Promise 也会 resolve,且结果是一个数组,数组中的元素顺序与输入 Promise 的顺序保持一致。
- 只有当所有输入的 Promise 都完成(无论成功或失败,但在 all 中通常指全部 resolve 才触发成功回调,若有一个 reject 则整体 reject)时,Promise.all 才会处理最终状态。为了实现这一逻辑,需要计数已完成的 Promise 数量。
- 只要输入的 Promise 数组中有一个被 reject,Promise.all 返回的 Promise 就会立即被 reject,无需等待其他 Promise 完成。
Promise.race 方法用于返回第一个完成(无论成功或失败)的 Promise 结果,其特点如下。
- Promise.race 返回一个新的 Promise 对象。
- 当输入为数组时,输出结果取决于数组中第一个完成(resolve 或 reject)的 Promise 的值或状态。
- 只要数组中有一个 Promise 执行了 resolve 或 reject,Promise.race 返回的 Promise 状态就会随之改变,并立即传递该结果。
const PENDING = 'pending' //等待
const FULFILLED = 'fulfilled' //成功
const REJECTED = 'rejected' //失败
const fulfilledCallback = [] //成功回调函数
const rejectedCallback = [] //失败回调函数
class MyPromise {
constructor (executor) {
try{
executor(this.resolve, this.reject)
} catch (e){
this.reject(e)
}
}
status = PENDING//promise的状态
value = undefined//成功之后的值
reason = undefined//失败之后的值
fulfilledCallback = [] //成功回调函数
rejectedCallback = [] //失败回调函数
resolve = value => {
//如果状态不是等待, 阻止程序继续往下执行
if(this.status !== PENDING){
return
}
this.status = FULFILLED
this.value = value
//判断成功回调是否存在,如果存在, 调用
// this.fulfilledCallback && this.fulfilledCallback(this.value)
while(this.fulfilledCallback.length) this.fulfilledCallback.shift()()
}
reject = reason => {
//如果状态不是等待, 阻止程序继续往下执行
if(this.status !== PENDING){
return
}
this.status = REJECTED
this.reason = reason
//判断失败回调是否存在,如果存在, 调用
// this.rejectedCallback && this.rejectedCallback(this.reason)
while(this.rejectedCallback.length) this.rejectedCallback.shift()()
}
then = (fulfilledCallback, rejectedCallback) => {
fulfilledCallback = fulfilledCallback ? fulfilledCallback : value => value
rejectedCallback = rejectedCallback ? rejectedCallback : reason => {throw reason}
let promise2 = new MyPromise((resolve, reject) => {
//判断状态
if(this.status === FULFILLED){
setTimeout(() => {
try {
//判断x 传过来的可能是promise,先查看promise返回的结果,在决定是用resolve还是reject,
//如果是普通值,直接调用resolve
let x = fulfilledCallback(this.value)
//外面加载完,才能获取到promise2,用异步解决
resolvePromise(promise2,x,resolve, reject)
} catch (error) {
reject(error)
}
},0)
}else if(this.status === REJECTED){
setTimeout(() => {
try {
//判断x 传过来的可能是promise,先查看promise返回的结果,在决定是用resolve还是reject,
//如果是普通值,直接调用resolve
let x = rejectedCallback(this.reason)
//外面加载完,才能获取到promise2,用异步解决
resolvePromise(promise2,x,resolve, reject)
} catch (error) {
reject(error)
}
},0)
}else{
//等待状态
this.fulfilledCallback.push(() => {
setTimeout(() => {
try {
//判断x 传过来的可能是promise,先查看promise返回的结果,在决定是用resolve还是reject,
//如果是普通值,直接调用resolve
let x = fulfilledCallback(this.value)
//外面加载完,才能获取到promise2,用异步解决
resolvePromise(promise2,x,resolve, reject)
} catch (error) {
reject(error)
}
},0)
});
this.rejectedCallback.push(() => {
setTimeout(() => {
try {
//判断x 传过来的可能是promise,先查看promise返回的结果,在决定是用resolve还是reject,
//如果是普通值,直接调用resolve
let x = rejectedCallback(this.reason)
//外面加载完,才能获取到promise2,用异步解决
resolvePromise(promise2,x,resolve, reject)
} catch (error) {
reject(error)
}
},0)
});
}
})
return promise2
}
static all (array) {
let result= []
let index = 0;
return new MyPromise((resolve, reject) => {
function addData (key, value) {
result[key] = value
index++
if (index === array.length) {
resolve(result)
}
}
for (let i = 0; i < array.length; i++) {
if (array[i] instanceof MyPromise) {
//promise对象
array[i].then(value => addData(i, value), reason => reject(reason))
} else {
//普通值, 放到数组里
addData(i, array[i])
}
}
})
}
static resolve (value) {
if(value instanceof MyPromise) return value
return new MyPromise(resolve => resolve(value))
}
finally (callback) {
return this.then(value => {
return MyPromise.resolve(callback()).then(() => value)
}, reason => {
return MyPromise.resolve(callback()).then(() => {throw reason})
})
}
catch (rejectedCallback) {
return this.then(undefined, rejectedCallback)
}
}
function resolvePromise(promise2,x,resolve, reject){
if(x === promise2){
return reject(new TypeError('啦啦啦啦'))
}
if(x instanceof MyPromise){
//是promise
//往下直接传
x.then(resolve,reject)
}else{
//普通值
resolve(x)
}
}
module.exports = MyPromise;至此,关于 JavaScript 手动实现 Promise 核心功能的示例代码讲解完毕。如需了解更多 JavaScript 实现 Promise 的相关内容,请搜索本站过往文章或继续浏览后续文章,感谢大家的支持!
JavaScript闭包与类(Class)的区别及适用场景对比
2026-11-05 15:48:57
JavaScript入门要学ES6吗?let与箭头函数等新特性解析
2026-11-05 14:49:16
JavaScript 8种数据类型详解:基本类型与引用类型的区别
2026-11-05 14:25:15
怎么在JavaScript中使用async/await优化Ajax异步流程
2026-11-05 13:56:15
JavaScript replace回调函数实现动态正则替换逻辑
2026-11-05 13:52:13
