前言
前言:Promise的出现为解决异步和毁掉地狱问题作出了巨大贡献,但是仅仅停留在会用的层面是不行的,只有深入其本质,我们才能体会到它的神秘之处。本文我就来介绍如何从0到1实现一个符合Promise A+规范的Promise,以及Promise的一些静态方法。
Promise A+ 规范详见promisesaplus.com/
Promise的实现
初步实现可以修改状态并且保留结果的Promise
- 要点1:executor类型检测
由下图可以看出,当executor不是Function类型的时候,会抛出TypeError的类型错误。
- 要点2:Promise构造函数要求传入一个函数,这个函数传入两个函数类型的参数(resolve,reject)用于改变Promise的状态和值。这个函数会立即执行,Promise的状态只能由pendding(等待)变成fulfilled(成功)和rejected(失败) 并且只能改变一次。
具体实现如下
class Promise{
constructor(executor) {
//不能相信用户的输入,参数校验
if(typeof executor !== 'function'){
throw new TypeError(`Promise resolver ${executor} is not a function`)
}
//初始化值
this.value = null //终值
this.reason = null //拒因
this.state = 'pending' //状态
const resolve = value => {
//状态只能从 pending => 其他,所以需要判断
if(this.state === 'pending'){
this.state = Promise.FULFILLED
this.value = value
}
}
const reject = reason => {
if(this.state === 'pending'){
this.state = Promise.REJECTED
this.reason = reason
}
}
//立即执行传入的executor
executor(resolve,reject)
}
}
Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'rejected'
then方法初步实现
then方法可以传入两个函数类型的参数:onFulfilled和onRejected,这两个参数是对应Promise状态改变后要执行的回调函数,在执行时会传入对应的Promise的值。
- 要点1:判断
onFulfilled和onRejected是否是函数类型,不是函数类型(或者没传,undefined)就赋一个默认回调来达到链式调用的穿透(传递)效果 - 要点2:传入的回调只有状态改变后才能调用(状态为pending的时候不能调用)
class Promise{
constructor(executor) {
if(typeof executor !== 'function'){
throw new TypeError(`Promise resolver ${executor} is not a function`)
}
this.value = null
this.reason = null
this.state = Promise.PENDING
const resolve = value => {
if(this.state === Promise.PENDING){
this.state = Promise.FULFILLED
this.value = value
}
}
const reject = reason => {
if(this.state === Promise.PENDING){
this.state = Promise.REJECTED
this.reason = reason
}
}
executor(resolve,reject)
}
then(onFulfilled,onRejected){
//参数校验
if(typeof onFulfilled !== 'function'){
onFulfilled = value => value
}
if(typeof onRejected !== 'function'){
onRejected = reason => {throw reason}
}
//不能在状态改变前调用
if(this.state === Promise.FULFILLED){
onFulfilled(this.value)
}
//不能在状态改变前调用
if(this.state === Promise.REJECTED){
onRejected(this.reason)
}
}
}
Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'rejected'
异步修改Promise状态
- 要点1:原版promise的then方法中的回调是异步执行的,验证如下,所以实现的Promise的回调也要异步执行
console.log(1)
const p = new Promise((resolve,reject)=>{
console.log(2)
resolve()
})
p.then(value=>{
console.log(4)
},err=>{
console.log(err)
})
console.log(3)
//这段代码的输出结果是1,2,3,4(原版Promise)
//但是放到上面一个小节中,输出结果是1,2,4,3,也就是说,then中的回调是立即执行了
- 要点2:在构造函数中的
executor执行外面加try...catch解决在executor中抛出异常的问题 - 要点3:在then中添加pending状态的判断,将回调存入数组等到状态改变的时候执行,解决在
executor中执行异步 ,延迟修改状态导致then中的回调函数没有执行的情况
class Promise{
constructor(executor) {
if(typeof executor !== 'function'){
throw new TypeError(`Promise resolver ${executor} is not a function`)
}
this.value = null
this.reason = null
this.state = Promise.PENDING
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = value => {
if(this.state === Promise.PENDING){
this.state = Promise.FULFILLED
this.value = value
//状态修改后执行(针对pending状态时存入的回调)
this.onFulfilledCallbacks.forEach(fn=>fn())
}
}
const reject = reason => {
if(this.state === Promise.PENDING){
this.state = Promise.REJECTED
this.reason = reason
//状态修改后执行(针对pending状态时存入的回调)
this.onRejectedCallbacks.forEach(fn=>fn())
}
}
//捕获executor中的异常
try {
executor(resolve,reject)
}catch (e) {
reject(e)
}
}
then(onFulfilled,onRejected){
if(typeof onFulfilled !== 'function'){
onFulfilled = value => value
}
if(typeof onRejected !== 'function'){
onRejected = reason => {throw reason}
}
if(this.state === Promise.FULFILLED){
//将回调异步执行
setTimeout(()=>{
onFulfilled(this.value)
})
}
if(this.state === Promise.REJECTED){
//将回调异步执行
setTimeout(()=>{
onRejected(this.reason)
})
}
//executor中异步修改状态,此时执行then的时候是pending状态,需要保存要执行的回调函数,等到状态修改后执行
if(this.state === Promise.PENDING){
this.onFulfilledCallbacks.push(()=>{
//将回调异步执行
setTimeout(()=>{
onFulfilled(this.value)
})
})
this.onRejectedCallbacks.push(()=>{
//将回调异步执行
setTimeout(()=>{
onRejected(this.reason)
})
})
}
}
}
Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'rejected'
module.exports = Promise
链式调用实现
- then返回值是一个新的promise
-
promise解决过程
- 如果
x === promise2 - 如果
x instanceof Promise - 如果
x是object || x是function
- 如果
- 如果then回调的返回值x是promise,并且这个promise的resolve中又返回一个promise,那么promise2的结果由这个resolve中的promise决定。(状态移交)
class Promise{
constructor(executor) {
if(typeof executor !== 'function'){
throw new TypeError(`Promise resolver ${executor} is not a function`)
}
this.value = null
this.reason = null
this.state = Promise.PENDING
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = value => {
if(this.state === Promise.PENDING){
this.state = Promise.FULFILLED
this.value = value
this.onFulfilledCallbacks.forEach(fn=>fn())
}
}
const reject = reason => {
if(this.state === Promise.PENDING){
this.state = Promise.REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach(fn=>fn())
}
}
try {
executor(resolve,reject)
}catch (e) {
reject(e)
}
}
then(onFulfilled,onRejected){
//如果onFulfilled不是函数,且promise1成功执行,promise2必须返回相同的终值(状态为fulfilled)
if(typeof onFulfilled !== 'function'){
onFulfilled = value => value
}
//如果onRejected不是函数,且promise1拒绝执行,promise2必须返回相同的拒绝原因(状态为rejected)
if(typeof onRejected !== 'function'){
onRejected = reason => {throw reason}
}
//返回值是Promise
let promise2 = new Promise((resolve,reject)=>{
if(this.state === Promise.FULFILLED){
setTimeout(()=>{
//如果onFulfilled或onRejected执行时抛出一个异常e,则返回的promise必须拒绝执行,并返回拒因e
try{
//如果有返回值,则执行promise解决过程
const x = onFulfilled(this.value)
Promise.resolvePromise(promise2, x, resolve, reject)
}catch (e){
reject(e)
}
})
}
if(this.state === Promise.REJECTED){
setTimeout(()=>{
try {
const x = onRejected(this.reason)
Promise.resolvePromise(promise2, x, resolve, reject)
}catch (e) {
reject(e)
}
})
}
if(this.state === Promise.PENDING){
this.onFulfilledCallbacks.push(()=>{
setTimeout(()=>{
try {
const x = onFulfilled(this.value)
Promise.resolvePromise(promise2, x, resolve, reject)
}catch (e){
reject(e)
}
})
})
this.onRejectedCallbacks.push(()=>{
setTimeout(()=>{
try {
const x = onRejected(this.reason)
Promise.resolvePromise(promise2, x, resolve, reject)
}catch (e){
reject(e)
}
})
})
}
})
return promise2
}
}
Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'rejected'
Promise.resolvePromise = function(promise2,x,resolve,reject){
//如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise(形成了链式调用)
if(promise2 === x){
reject(new TypeError('Chaining cycle detected for promise'))
}
//标记如果x是对象或函数且有then方法时,回调只能调一次,避免出现{then(a,b){ a() ;a() }}多次调用,多次执行的情况
let flag = false
//如果返回值x是promise类型,那么then返回的promise的类型与这个promise的执行结果一致
if(x instanceof Promise){
//什么时候执行结束?执行了x.then中的回调的时候说明promise(x)中的executor执行结束了
x.then(value=>{
//这里不应该简单的执行resolve,因为如果x的resolve的参数是一个promise对象的话,promise2的结果由这个参数决定
Promise.resolvePromise(promise2,value,resolve,reject)
},reason=>{
reject(reason)
})
}
//如果x是对象或者是函数,注意:null也是object类型,所以要特判不能为null
else if(x !== null && (typeof x === 'object' || typeof x === 'function')){
//可能x对象的then方法中会抛出异常
try{
//规范要求我们先将x.then存储到then中,避免重复从对象中取值
const then = x.then
//判断是不是thenable对象(有then方法的对象)
if(typeof then === 'function'){
then.call(
x,
value => {
if(flag) return
flag = true
Promise.resolvePromise(promise2,value,resolve,reject)
},
reason =>{
if(flag) return
flag = true
reject(reason)
})
}else{
if(flag) return
flag = true
//不是thenable对象的话,就是普通对象,直接resolve
resolve(x)
}
}catch (e) {
if(flag) return
flag = true
reject(e)
}
}
//是普通值
else{
resolve(x)
}
}
Promise的静态方法实现
其实Promise的静态方法,无非就是取决于何时调用resolve和reject改变返回的Promise状态。下面我们来一个个实现。
Promise.all
Promise.all方法是,传入的所有Promise都成功,返回成功的状态以及这些成功的值组成的数组,有一个失败就直接返回失败的结果。
Promise.prototype.all = function (arr) {
return new Promise((resolve, reject) => {
let res = [];
//遍历数组,给每个promise对象指定then回调
for (const promise of arr) {
promise.then((data) => {
res.push(data);
//所有promise都为成功状态时,改变返回的Promise的状态
if (res.length === arr.length) resolve(res);
}, reject);
}
});
};
Promise.allSettled
Promise.allSettled方法是,传入的所有Promise状态都改变了,才改变返回的Promise的状态,并且返回的Promise中保存的是所有传入的Promise的状态和值组成的数组。
Promise.prototype.allSettled = function (arr) {
return new Promise((resolve, reject) => {
let res = [];
//遍历数组,给每个promise对象指定then回调
for (const promise of arr) {
promise.then(
(data) => {
res.push({ value: data, status: Promise.FULFILLED });
//所有promise状态都改变时,改变返回的Promise的状态
if (res.length === arr.length) resolve(res);
},
(err) => {
res.push({ value: err, status: Promise.REJECTED });
//所有promise状态都改变时,改变返回的Promise的状态
if (res.length === arr.length) reject(res);
}
);
}
});
};
Promise.race
Promise.race方法是,传入一个Promise数组,返回的Promise的状态取决于第一个改变状态的promise对象。
Promise.prototype.race = function (arr) {
return new Promise((resolve, reject) => {
for (const promise of arr) {
//当某个promise状态修改的时候,直接修改返回的promise的状态
promise.then(resolve,reject);
}
});
};
Promise.any
Promise.any方法是,传入一个Promise数组,必须等到一个Promise成功的结果才改变返回的Promise的状态为成功,否则只有当所有Promise都为失败状态时,才改变返回的Promise的状态为失败,并且保存所有失败原因。
Promise.prototype.any = function (arr) {
return new Promise((resolve, reject) => {
let res = [];
//遍历数组,给每个promise对象指定then回调
for (const promise of arr) {
promise.then(resolve, (err) => {
res.push(err);
//所有promise都为失败状态时,改变返回的Promise的状态
if (res.length === arr.length) reject(res);
});
}
});
};