文章目录
一、基础概念理解
1.0 Promise的简化代码逻辑
// 以es5为例
function MyPromise(exec){
this.state = 'pending'; // 初始状态
this.data = undefined; // 存储结果 / 错误原因
this.onFulfilledCallbacks = []; // 成功回调队列
this.onRejectedCallbacks = []; // 失败回调队列
function resolve(value){
// 1. vlaue是Promise类型,需判断状态,重新包裹成Promise
// 2. vlaue非Promise类型,说明是同步代码,直接改变当前Promise状态,设置Promise的成功结果,执行成功回调队列
// ...
}
function reject(reason){
// 1. 直接修改Promise状态,设置Promise的失败原因,执行失败回调队列
// ...
}
try {
exec(resolve, reject);
} catch (error) {
reject(error)
}
}
const resolvePromise = (promise2, x, resolve, reject) => {
// 判断链式是否无限循环
if (promise2 === x) return reject(new TypeError('Chaining cycle detected for promise!'))
// ...
// 循环递归直至promise为非pending态
let then = x.then;
if (typeof then === 'function') {
then.call(
x,
y => resolvePromise(promise2, y, resolve, reject),
r => reject(r)
);
} else {
resolve(x);
}
}
MyPromise.prototype.then = function (onResolved, onRejected) {
var self = this;
var promise2;
onResolved = typeof onResolved === 'function' ? onResolved : function (value) { return value };
onRejected = typeof onRejected === 'function' ? onRejected : function (reason) { throw reason };
if (self.status === 'resolved') {
// 1. 当前Promise已完成,可直接调用户的resolve方法,返回值可能有
// - 普通值:直接resolve
// - Promise对象:等待其状态变化
// 2. then返回值均为Promise,需对用户resolve方法的返回值,再做Promise包裹
// 3. resolvePromise处理各种返回值类型,直至所有异步态结束
}
if (self.status === 'rejected') {
// 1. 同resolve相关逻辑,区别在于,调用户的reject方法获取当前Promise的值
}
if (self.status === 'pending') {
// 1. 当前Promise未完成,不能立即调用户的resolve或者reject方法
// 2. 使用成功回调队列和失败回调队列,先存储调用对应方法的回调
}
}
1.1 Promise的状态机
Promise是一种异步编程解决方案,它有三种状态:
- pending(等待态):初始状态,既没有被兑现,也没有被拒绝。
- fulfilled(已兑现):操作成功完成。
- rejected(已拒绝):操作失败。
状态转换规则:
- pending → fulfilled (只能转换一次)
- pending → rejected (只能转换一次)
1.2 状态转换规则
Promise的状态一旦改变就不能再修改。这种不可变性是Promise设计的核心原则之一。
1.3 then方法的链式调用原理
then方法返回的是一个新的Promise实例,而不是原来的Promise实例。这使得链式调用成为可能:
promise
.then(result => {
// 处理结果
return processResult(result);
})
.then(processedResult => {
// 继续处理
return finalResult(processedResult);
})
.catch(error => {
// 捕获错误
});
1.4 微任务队列机制
Promise的回调是通过微任务队列执行的,这保证了异步操作的顺序性。微任务会在当前宏任务执行结束后立即执行。
二、核心数据结构设计
2.1 Promise构造函数
class MyPromise {
constructor(executor) {
this.state = 'pending'; // 初始状态
this.value = undefined; // 存储结果
this.reason = undefined; // 存储错误原因
this.onFulfilledCallbacks = []; // 成功回调队列
this.onRejectedCallbacks = []; // 失败回调队列
// 执行器函数
try {
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
}
2.2 状态管理
状态管理需要确保状态只能改变一次:
resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
// 执行所有成功回调
this.onFulfilledCallbacks.forEach(callback => callback(value));
}
}
reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 执行所有失败回调
this.onRejectedCallbacks.forEach(callback => callback(reason));
}
}
2.3 回调队列
回调队列用于存储then方法注册的回调函数,直到Promise状态改变时再执行。
2.4 值传递机制
值传递需要处理thenable对象和Promise的穿透特性:
// 处理thenable对象
const resolvePromise = (promise2, x, resolve, reject) => {
// 以防这种情况
// const p = Promise.resolve().then(()=>p)
// then方法返回的Promise 和 ()=>p 返回的Promise是同一个
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
if ((x !== null && typeof x === 'object') || typeof x === 'function') {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(
x,
y => resolvePromise(promise2, y, resolve, reject),
r => reject(r)
);
} else {
resolve(x);
}
} catch (error) {
reject(error);
}
} else {
resolve(x);
}
}
三、关键方法实现
3.1 then方法
then(onFulfilled, onRejected) {
// 确保onFulfilled和onRejected是函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
// 创建新的Promise
const promise2 = new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.state === 'pending') {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
}
3.2 resolve/reject函数
resolve和reject函数需要处理以下情况:
- 传入Promise对象时,需要等待其状态改变
- 传入thenable对象时,需要调用其then方法
- 传入普通值时,直接改变状态
3.3 链式调用处理
链式调用的核心是每个then方法都返回一个新的Promise,并且需要处理返回值的穿透特性。
3.4 错误处理机制
错误处理需要考虑:
- 执行器函数中的同步错误
- then方法中回调函数的执行错误
- 链式调用中的错误传递
四、完整代码实现
// 基础Promise类
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(callback => callback());
}
}
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(callback => callback());
}
}
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
const promise2 = new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.state === 'pending') {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise2;
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onFinally) {
return this.then(
value => MyPromise.resolve(onFinally()).then(() => value),
reason => MyPromise.resolve(onFinally()).then(() => { throw reason })
);
}
}
const resolvePromise = (promise2, x, resolve, reject) => {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
if ((x !== null && typeof x === 'object') || typeof x === 'function') {
try {
let then = x.then;
// 判断是否thenable
if (typeof then === 'function') {
then.call(
x,
y => resolvePromise(promise2, y, resolve, reject),
r => reject(r)
);
} else {
resolve(x);
}
} catch (error) {
reject(error);
}
} else {
resolve(x);
}
}
// 静态方法
MyPromise.resolve = (value) => {
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value));
}
MyPromise.reject = (reason) => {
return new MyPromise((resolve, reject) => reject(reason));
}
MyPromise.all = (promises) => {
return new MyPromise((resolve, reject) => {
const results = [];
let completedCount = 0;
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(
value => {
results[index] = value;
completedCount++;
if (completedCount === promises.length) {
resolve(results);
}
},
reason => reject(reason)
);
});
});
}
MyPromise.race = (promises) => {
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
MyPromise.resolve(promise).then(resolve, reject);
});
});
}
// 测试代码
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 1000);
});
promise
.then(result => {
console.log('Result:', result);
return '处理后的数据';
})
.then(processedResult => {
console.log('Processed:', processedResult);
throw new Error('测试错误');
})
.catch(error => {
console.error('Error:', error.message);
});
// Promise.all测试
MyPromise.all([
MyPromise.resolve(1),
MyPromise.resolve(2),
MyPromise.resolve(3)
]).then(results => console.log('All results:', results));
// Promise.race测试
MyPromise.race([
new MyPromise(resolve => setTimeout(() => resolve('第一个完成'), 500)),
new MyPromise(resolve => setTimeout(() => resolve('第二个完成'), 1000))
]).then(result => console.log('Race result:', result));
总结
Promise的实现原理涉及状态管理、回调队列、微任务机制等多个核心概念。通过理解这些原理,我们可以更好地使用Promise进行异步编程,并且在需要时实现自定义的Promise类。
完整的Promise实现需要考虑很多边界情况和规范细节,上述代码是一个简化的版本,实际的Promise/A+规范要复杂得多。建议在学习过程中结合规范文档和测试用例进行深入理解。