手写Promise及其实例方法和静态方法的代码记录
一直很想搞清楚promise底层的原理,今天在找资料时阅读到了下面文章,照着阅读并复刻了一下代码
再次感谢原文作者:圆圆01
手把手一行一行代码教你“手写Promise“,完美通过 Promises/A+ 官方872个测试用例-作者:圆圆01
手写实现 Promise 全部实例方法和静态方法,来看看 Promise.all、Promise.race 和 Promise.any 都是怎么实现的-作者:圆圆01
// 手写Promise类
class myPromise {
// 创建状态管理变量
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
// Promise构造器
constructor(func) {
// 创建PromiseState状态属性,默认为PENDING
this.PromiseState = myPromise.PENDING;
//创建PromiseResult保存执行结果(成功/失败),初始值为null
this.PromiseResult = null;
//创建onFulfilledCallbacks和onRejectedCallbacks数组保存回调函数,防止没有resolve和reject的情况下then方法无法进行判断
// 使用数组保存是考虑到后续的链式调用,数组支持先入先出
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
// 使用trycatch创建实例,防止创建实例时Error信息无法正常捕获
try {
// 创建Promise实例时,需要传入一个函数类型参数
// 单纯使用 func(this.resolve, this.reject);会出现this指向问题,使用bind绑定this
func(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
//如果有错,直接调用reject,并将错误信息作为参数传给reject
//注意此处不需要bind来指定this,因为是直接执行的,而不是在实例创建后执行
this.reject(error);
}
}
//创建func中两个函数参数,使用this获取
// resolve添加一个result形参,并在调用时赋值给this.PromiseResult
resolve(result) {
// 判断状态,(PENDING -> FULFILLED)
if (this.PromiseState === myPromise.PENDING) {
this.PromiseState = myPromise.FULFILLED;
//调用时赋值给this.PromiseResult
this.PromiseResult = result;
// 检查是否有待执行的函数,有则执行
this.onFulfilledCallbacks.forEach(callback => {
callback(result);
});
}
}
// reject添加一个reason形参,并在调用时赋值给this.PromiseResult
reject(reason) {
// 判断状态,(PENDING -> REJECTED)
if (this.PromiseState === myPromise.PENDING) {
this.PromiseState = myPromise.REJECTED;
//调用时赋值给this.PromiseResult
this.PromiseResult = reason;
// 检查是否有待执行的函数,有则执行
this.onRejectedCallbacks.forEach(callback => {
callback(reason);
});
}
}
// 支持链式调用的then方法,在这个then的下方是原先手写时,最初的then方法,这里保留下方注释
/**
* [注册fulfilled状态/rejected状态对应的回调函数]
* @param {function} onFulfilled fulfilled状态时 执行的函数
* @param {function} onRejected rejected状态时 执行的函数
* @returns {function} newPromsie 返回一个新的promise对象
*/
then(onFulfilled, onRejected) {
//为了支持链式调用且符合Promise/A+规范,then方法必须返回一个新的Promise实例
const promise2 = new myPromise((resolve, reject) => {
//Fulfilled状态
if (this.PromiseState === myPromise.FULFILLED) {
setTimeout(() => {
try {
if (typeof onFulfilled !== 'function') {
//如果onFulfilled不是一个函数并且promise1成功执行,promise2必须成功执行并返回相同的值
resolve(this.PromiseResult);
} else {
//如果onFulfilled返回一个值x,则执行[[Resolve]](promise2,x)
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
//如果onFulfilled抛出一个异常,则promise2必须拒绝执行,并返回拒绝原因error
reject(error);
}
});
};
//Rejected状态
if (this.PromiseState === myPromise.REJECTED) {
setTimeout(() => {
try {
if (typeof onRejected !== 'function') {
//如果onRejected不是函数并promise1拒绝执行,promise2必须拒绝执行并返回相同的拒绝原因
reject(this.PromiseResult);
} else {
//如果onRejected返回一个值x,则执行[[Resolve]](promise2,x)
let x = onRejected(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
//如果onRejected抛出一个异常,则promise2必须拒绝执行,并返回拒绝原因error
reject(error);
}
})
}
//Pending状态
if (this.PromiseState === myPromise.PENDING) {
//push到数组
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
if (typeof onFulfilled !== 'function') {
//如果onFulfilled不是一个函数并且promise1成功执行,promise2必须成功执行并返回相同的值
resolve(this.PromiseResult);
} else {
//如果onFulfilled返回一个值x,则执行[[Resolve]](promise2,x)
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
//如果onFulfilled抛出一个异常,则promise2必须拒绝执行,并返回拒绝原因error
reject(error);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
if (typeof onRejected !== 'function') {
//如果onRejected不是函数并promise1拒绝执行,promise2必须拒绝执行并返回相同的拒绝原因
reject(this.PromiseResult);
} else {
//如果onRejected返回一个值x,则执行[[Resolve]](promise2,x)
let x = onRejected(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
//如果onRejected抛出一个异常,则promise2必须拒绝执行,并返回拒绝原因error
reject(error);
}
});
});
}
});
return promise2;
}
// //then方法用于处理成功(onFulfilled)和失败(onRejected)后调用的函数
// //then方法内部还需要添加PENDING状态的维护,保存回调函数,在resolve或reject之后再调用
// // 内部使用宏任务,保证then方法是异步执行,等待执行栈为空后再执行
// then(onFulfilled, onRejected) {
// //如果调用then时,没有传入函数,对于成功则返回成功的结果,失败则直接抛出一个错误
// onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : result => result;
// onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
// //添加PENDING状态的维护,保存回调函数,在resolve或reject之后再调用
// // 同样的,也要使用异步
// if (this.PromiseState === myPromise.PENDING) {
// this.onFulfilledCallbacks.push(() => {
// setTimeout(() => {
// onFulfilled(this.PromiseResult);
// })
// });
// this.onRejectedCallbacks.push(() => {
// setTimeout(() => {
// onRejected(this.PromiseResult);
// })
// })
// }
// // 如果成功,则执行成功逻辑,并保持状态不变
// if (this.PromiseState === myPromise.FULFILLED) {
// // 使用setTimeout传入执行结果,保证异步
// setTimeout(() => { onFulfilled(this.PromiseResult); });
// }
// // 如果失败,则执行失败逻辑,并保持状态不变
// if (this.PromiseState === myPromise.REJECTED) {
// // 使用setTimeout传入执行结果,保证异步
// setTimeout(() => { onRejected(this.PromiseResult); })
// }
// }
}
/**
* 对resolve()、reject() 进行改造增强 针对resolve()和reject()中不同值情况 进行处理
* @param {promise} promise2 promise1.then方法返回的新的promise对象
* @param {[type]} x promise1中onFulfilled或onRejected的返回值
* @param {[type]} resolve promise2的resolve方法
* @param {[type]} reject promise2的reject方法
*/
function resolvePromise(promise2, x, resolve, reject) {
//如果 promise2 和 x 指向同一对象,以 TypeError 为拒绝原因拒绝执行 promise2,因为这会导致无限的循环
if (promise2 === x) {
throw new TypeError("Chaining cycle detected for promise");
};
//如果x为Promise,则使promise2接受x的状态
if (x instanceof myPromise) {
// x拿到的是promise1的返回,并且返回是一个Promise,所以继续递归执行,直到不是一个Promise返回
x.then(y => {
resolvePromise(promise2, y, resolve, reject);
}, reject)
} else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
//如果x为对象或函数,这里注意显式判断是不是null,因为typeof null也会返回object(js历史遗留问题)
try {
//如果x为对象或函数,则把x.then赋值给then
//这一步是为了兼容“thenable”对象,保证你的 Promise 实现能和各种“类Promise对象”无缝衔接,符合规范。
var then = x.then;
} catch (error) {
//如果在获取x.then的过程中抛出错误error,则以error为原因拒绝promise2
reject(error);
};
//如果then是函数,将x作为then函数的作用域this
if (typeof then === 'function') {
//避免多次调用
let called = false;
try {
then.call(
//x作为函数的作用域this
x,
y => {
//如果resolvePromise以值y作为参数被调用,则运行[[Resolve]](promise,y)
if (called) return; //防止重复调用
called = true;
resolvePromise(promise2, y, resolve, reject)
},
r => {
//如果rejectPromise以拒绝原因r为参数被调用,则以r为拒绝原因拒绝promise
if (called) return; // 防止重复调用
called = true;
reject(r);
}
)
} catch (error) {
//如果调用then方法的过程抛出了错误error
//如果resolvePromise或rejectPromise已被调用,则忽略错误
if (called) return;
called = true;
//以error为拒绝原因拒绝promise
reject(error);
}
} else {
//如果then不是函数,则以x为参数执行promise
resolve(x);
}
} else {
//如果x不为对象或者函数,则以x为参数执行promise
return resolve(x)
}
}
//测试需要的代码
myPromise.deferred = function () {
let result = {};
result.promise = new myPromise((resolve, reject) => {
result.resolve = resolve;
result.reject = reject;
});
return result;
}
module.exports = myPromise;// 手写Promise类 + 实例方法 + 静态方法
class myPromise {
// 创建状态管理变量
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
// Promise构造器
constructor(func) {
// 创建PromiseState状态属性,默认为PENDING
this.PromiseState = myPromise.PENDING;
//创建PromiseResult保存执行结果(成功/失败),初始值为null
this.PromiseResult = null;
//创建onFulfilledCallbacks和onRejectedCallbacks数组保存回调函数,防止没有resolve和reject的情况下then方法无法进行判断
// 使用数组保存是考虑到后续的链式调用,数组支持先入先出
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
// 使用trycatch创建实例,防止创建实例时Error信息无法正常捕获
try {
// 创建Promise实例时,需要传入一个函数类型参数
// 单纯使用 func(this.resolve, this.reject);会出现this指向问题,使用bind绑定this
func(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
//如果有错,直接调用reject,并将错误信息作为参数传给reject
//注意此处不需要bind来指定this,因为是直接执行的,而不是在实例创建后执行
this.reject(error);
}
}
//创建func中两个函数参数,使用this获取
// resolve添加一个result形参,并在调用时赋值给this.PromiseResult
resolve(result) {
// 判断状态,(PENDING -> FULFILLED)
if (this.PromiseState === myPromise.PENDING) {
this.PromiseState = myPromise.FULFILLED;
//调用时赋值给this.PromiseResult
this.PromiseResult = result;
// 检查是否有待执行的函数,有则执行
this.onFulfilledCallbacks.forEach(callback => {
callback(result);
});
}
}
// reject添加一个reason形参,并在调用时赋值给this.PromiseResult
reject(reason) {
// 判断状态,(PENDING -> REJECTED)
if (this.PromiseState === myPromise.PENDING) {
this.PromiseState = myPromise.REJECTED;
//调用时赋值给this.PromiseResult
this.PromiseResult = reason;
// 检查是否有待执行的函数,有则执行
this.onRejectedCallbacks.forEach(callback => {
callback(reason);
});
}
}
/*
* [注册fulfilled状态/rejected状态对应的回调函数]
* @param {function} onFulfilled fulfilled状态时 执行的函数
* @param {function} onRejected rejected状态时 执行的函数
* @returns {function} newPromsie 返回一个新的promise对象
*/
then(onFulfilled, onRejected) {
//为了支持链式调用且符合Promise/A+规范,then方法必须返回一个新的Promise实例
const promise2 = new myPromise((resolve, reject) => {
//Fulfilled状态
if (this.PromiseState === myPromise.FULFILLED) {
setTimeout(() => {
try {
if (typeof onFulfilled !== 'function') {
//如果onFulfilled不是一个函数并且promise1成功执行,promise2必须成功执行并返回相同的值
resolve(this.PromiseResult);
} else {
//如果onFulfilled返回一个值x,则执行[[Resolve]](promise2,x)
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
//如果onFulfilled抛出一个异常,则promise2必须拒绝执行,并返回拒绝原因error
reject(error);
}
});
};
//Rejected状态
if (this.PromiseState === myPromise.REJECTED) {
setTimeout(() => {
try {
if (typeof onRejected !== 'function') {
//如果onRejected不是函数并promise1拒绝执行,promise2必须拒绝执行并返回相同的拒绝原因
reject(this.PromiseResult);
} else {
//如果onRejected返回一个值x,则执行[[Resolve]](promise2,x)
let x = onRejected(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
//如果onRejected抛出一个异常,则promise2必须拒绝执行,并返回拒绝原因error
reject(error);
}
})
}
//Pending状态
if (this.PromiseState === myPromise.PENDING) {
//push到数组
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
if (typeof onFulfilled !== 'function') {
//如果onFulfilled不是一个函数并且promise1成功执行,promise2必须成功执行并返回相同的值
resolve(this.PromiseResult);
} else {
//如果onFulfilled返回一个值x,则执行[[Resolve]](promise2,x)
let x = onFulfilled(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
//如果onFulfilled抛出一个异常,则promise2必须拒绝执行,并返回拒绝原因error
reject(error);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
if (typeof onRejected !== 'function') {
//如果onRejected不是函数并promise1拒绝执行,promise2必须拒绝执行并返回相同的拒绝原因
reject(this.PromiseResult);
} else {
//如果onRejected返回一个值x,则执行[[Resolve]](promise2,x)
let x = onRejected(this.PromiseResult);
resolvePromise(promise2, x, resolve, reject);
}
} catch (error) {
//如果onRejected抛出一个异常,则promise2必须拒绝执行,并返回拒绝原因error
reject(error);
}
});
});
}
});
return promise2;
}
/**
* Promise.resolve()
* @param {[type]} value 要解析为promise的值
*/
static resolve = function (value) {
//如果这个值是一个promise,则返回这个promise
if (value instanceof myPromise) {
return value;
} else if (value instanceof Object && 'then' in value) {
//如果这个值是thenable的,返回的promise要“跟随”这个thenable的对象,并采用它的最终值
return new myPromise((resolve, reject) => {
value.then(resolve, reject);
});
} else {
//否则返回的promise将以此值完成,以此值为参数执行resolve
return new myPromise(resolve => {
resolve(value);
})
}
}
/**
* Promise.reject()
* @param {[type]} reason 表示Promise被拒绝的原因
* @returns
*/
static reject = function (reason) {
return new myPromise((resolve, reject) => {
reject(reason);
})
}
/**
* Promise.prototype.catch()
* @params {*} onRejected
* @returns
*/
catch(onRejected) {
//直接复用this.then,只是设置onResolve为undefined即可
return this.then(undefined, onRejected);
}
/**
* Promise.prototype.finally()
* @params {*} 无论结果是fulfilled或是rejected,都会执行这个finnaly回调函数
* @returns
*/
finally(callback) {
return this.then(callback, callback);
}
/**
* Promise.all
* @param {iterable} promises 存储promise的iterable类型
* @returns
*/
static all(promises) {
return new myPromise((resolve, reject) => {
//检验是否为iterable
if (Array.isArray(promises)) {
//存储结果
let result = [];
//计数器
let count = 0;
//如果传入的对象是一个空的可迭代对象,则返回一个完成状态的Promise
if (promises.length === 0) {
return resolve(promises);
}
//遍历可迭代对象
promises.forEach((item, index) => {
//对每个item执行resovle,resolve内部会判断是否为iterable,并且还能处理thennable和普通值
myPromise.resolve(item).then(value => {
count++;
result[index] = value;
count === promises.length && resolve(result);
}, reason => {
reject(reason)
})
})
// //遍历可迭代对象(旧版)
// promises.forEach((item, index) => {
// //判断参数是否为promise对象
// if (item instanceof myPromise) {
// //手动调用
// myPromise.resolve(item).then(
// value => {
// count++;
// //存储结果
// result[index] = value;
// //等待所有promise完成,或遇到第一次失败
// count === promises.length && resolve(result);
// },
// reason => {
// // 如果传入的所有promises有一个失败,不管其他promises是否完成,以该失败的信息返回整个失败回调
// reject(reason);
// })
// } else {
// //参数非promise对象,原样返回在结果数组中
// count++;
// result[index] = item;
// //等待所有promise完成,或遇到第一次失败
// count === promises.length && resolve(result);
// }
// })
} else {
//如果不是iterable对象
return reject(new TypeError('Argument is not iterable'));
}
})
}
/**
* Promise.allSettled
* @param {iterable} promises 存储promise的iterable类型
* @returns
*/
static allSettled(promises) {
return new myPromise((resolve, reject) => {
//判断是否iterable
if (Array.isArray(promises)) {
//存储结果
let result = [];
//计数器
let count = 0;
//如果传入的是一个空数组,则直接返回一个resolved,内容为这个空数组
if (promises.length === 0) return resolve(promises);
//遍历promises
promises.forEach((item, index) => {
//通过静态方法resolve统一处理
myPromise.resolve(item).then(
value => {
count++;
//按标准存储一个对象
result[index] = {
status: 'fulfilled',
value
};
//所有promise都完成后返回这个结果
count === promises.length && resolve(result);
},
reason => {
count++;
//按标准存储一个对象
result[index] = {
status: 'rejected',
reason
}
//所有promise都完成后返回这个结果
count === promises.length && resolve(result);
})
})
} else {
return reject(new TypeError('Argument is not iterable'));
}
})
}
/**
* Promise.any
* @param {iterable} promises 存储promise的iterable类型
* @returns
*/
static any(promises) {
return new myPromise((resolve, reject) => {
//判断是否iterable
if (Array.isArray(promises)) {
//存储所有错误结果
let errors = [];
//计数器
let count = 0;
//如果传入的promises是空的可迭代对象,则返回一个失败状态的promise,reason为一个特殊的Error类型
if (promises.length === 0) return reject(new AggregateError('All promises are rejected'));
//遍历promises
promises.forEach((item, index) => {
//通过resolve静态方法统一处理
myPromise.resolve(item).then(
value => {
//只要其中一个成功,就直接返回
resolve(value);
},
reason => {
count++;
//存储失败的结果
errors.push(reason);
//如果全部都失败了,则返回一个失败的promise,reason为一个特殊类型的Error,并传递errors数组
count === promises.length && reject(new AggregateError(errors))
}
)
})
} else {
return reject(new TypeError('Argument is not iterable'));
}
})
}
/**
* Promise.race
* @param {iterable} promises 存储promise的iterable类型
* @returns
*/
static race(promises) {
return new myPromise((resolve, reject) => {
//判断是否iterable
if (Array.isArray([promises])) {
//如果可迭代对象为空,则返回的promise将一直处于PENDING
if (promises.length > 0) {
//遍历promises
promises.forEach((item) => {
// Promise.race 将解析为迭代中找到的第一个值
myPromise.resolve(item).then(resolve, reject)
})
}
} else {
return reject(new TypeError('Argument is not iterable'));
}
})
}
}
/**
* 对resolve()、reject() 进行改造增强 针对resolve()和reject()中不同值情况 进行处理
* @param {promise} promise2 promise1.then方法返回的新的promise对象
* @param {[type]} x promise1中onFulfilled或onRejected的返回值
* @param {[type]} resolve promise2的resolve方法
* @param {[type]} reject promise2的reject方法
*/
function resolvePromise(promise2, x, resolve, reject) {
//如果 promise2 和 x 指向同一对象,以 TypeError 为拒绝原因拒绝执行 promise2,因为这会导致无限的循环
if (promise2 === x) {
throw new TypeError("Chaining cycle detected for promise");
};
//如果x为Promise,则使promise2接受x的状态
if (x instanceof myPromise) {
// x拿到的是promise1的返回,并且返回是一个Promise,所以继续递归执行,直到不是一个Promise返回
x.then(y => {
resolvePromise(promise2, y, resolve, reject);
}, reject)
} else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
//如果x为对象或函数,这里注意显式判断是不是null,因为typeof null也会返回object(js历史遗留问题)
try {
//如果x为对象或函数,则把x.then赋值给then
//这一步是为了兼容“thenable”对象,保证你的 Promise 实现能和各种“类Promise对象”无缝衔接,符合规范。
var then = x.then;
} catch (error) {
//如果在获取x.then的过程中抛出错误error,则以error为原因拒绝promise2
reject(error);
};
//如果then是函数,将x作为then函数的作用域this
if (typeof then === 'function') {
//避免多次调用
let called = false;
try {
then.call(
//x作为函数的作用域this
x,
y => {
//如果resolvePromise以值y作为参数被调用,则运行[[Resolve]](promise,y)
if (called) return; //防止重复调用
called = true;
resolvePromise(promise2, y, resolve, reject)
},
r => {
//如果rejectPromise以拒绝原因r为参数被调用,则以r为拒绝原因拒绝promise
if (called) return; // 防止重复调用
called = true;
reject(r);
}
)
} catch (error) {
//如果调用then方法的过程抛出了错误error
//如果resolvePromise或rejectPromise已被调用,则忽略错误
if (called) return;
called = true;
//以error为拒绝原因拒绝promise
reject(error);
}
} else {
//如果then不是函数,则以x为参数执行promise
resolve(x);
}
} else {
//如果x不为对象或者函数,则以x为参数执行promise
return resolve(x)
}
}
module.exports = myPromise;