面试官:“请写出 Promise 的类方法和实例方法”

1,213 阅读10分钟

准备工作

1.Promise首先要接收一个函数当作参数,函数里又分别带有两个参数,分别是resolve回调和reject回调

2.Promise的状态有三种:等待(pending)、已完成(fulfilled)、已拒绝(rejected),并且状态只能由等待到完成或者等待到拒接

3.初始化状态 等待(pending)

     const PHB_PENDING = 'pending';
      const PHB_FULFILLED = 'fulfilled';
      const PHB_REJECTED = 'rejected';
      class PHBPromise {
        constructor(executor) {
          // 初始化状态  pending(未决定)
          this.state = PHB_PENDING;
          // 成功回调
          let resolve = () => {
            console.log('成功');
          };
          // 失败回调
          let reject = () => {
            console.log('失败');
          };

          // 执行接收的函数并传入函数参数,executor也会可能存在异常,因此通过try/catch来捕获一下异常情况
          try {
            executor(resolve, reject);
          } catch (error) {
            reject(error);

        }
      }
      let phbPromise = new PHBPromise((resolve, reject) => {
        resolve('成功');
      });

then方法

1.先简单搭建骨架

new phbPromise可以调用多个.then 所以成功回调、失败回调都使用数组存放

this.onFulfilled = []; //成功 this.onRejected = []; //失败

  then(onfulfilled, onrejected) {
          this.onFulfilled.push(onfulfilled);
          this.onRejected.push(onrejected);
   }

状态只能由等待到完成或者等待到拒接
进入rosolve修改状态为已完成(fulfilled),进入reject,修改状态为已拒绝(rejected)
这个时候我们执行下代码看下有什么问题

 // “Promise的三种状态: pending、fulfilled、rejected(等待,已完成,已拒绝)
      const PHB_PENDING = 'pending';
      const PHB_FULFILLED = 'fulfilled';
      const PHB_REJECTED = 'rejected';
      class PHBPromise {
        constructor(executor) {
          this.state = PHB_PENDING// 初始化状态  pending(等待)
          this.value = null//成功的结果或者失败的结果
          this.onFulfilled = []; //成功的回调
          this.onRejected = []; //失败的回调
          // 成功回调
          let resolve = value => {
            if (this.state === PHB_PENDING) {
              this.value = value;
              this.state = PHB_FULFILLED//修改状态为已完成(fulfilled)
              this.onFulfilled.forEach(item => {
                item(this.value);
              });
            }
          };
          // 失败回调
          let reject = reason => {
            if (this.state === PHB_PENDING) {
              this.value = reason;
              this.state = PHB_REJECTED//修改状态为已拒绝(rejected)
              this.onRejected.forEach(item => {
                item(this.value);
              });
            }
          };
          // 执行接收的函数并传入函数参数
          executor(resolve, reject);
        }
        then(onfulfilled, onrejected) {
          this.onFulfilled.push(onfulfilled);
          this.onRejected.push(onrejected);
        }
      }
      let phbPromise = new PHBPromise((resolve, reject) => {
        resolve('成功');
      });
      // 调用.then方法
      phbPromise.then(
        res => {
          console.log(res);
        },
        err => {
          console.log(err);
        }
      );

这个时候我们可以发现控制台没有输出。
为什么没有输出?不是已经调用了resolve?
答:在执行resolve时, phbPromise.then还未调用,还未把函数添加到this.onFulfilled,所以这个时候this.onFulfilled还是一个空数组。

then方法bug解决方案

在执行resolve先把它添加到微任务中,这个时候并不会阻塞,会继续执行后面代码 phbPromise.then,等同步任务都执行完成后再去微任务中执行resolve代码,,这个时候this.onFulfilled就有值了
如果还不太了解同步或异步任务,可以去看下事件循环机制(Event Loop)

 let phbPromise = new PHBPromise((resolve, reject) => {
        resolve('成功');//添加微任务 代码继续向下执行
      });
      // 调用.then方法
      phbPromise.then(
        res => {
          console.log(res);
        },
        err => {
          console.log(err);
        }
      );

         // 成功回调
          let resolve = value => {
            if (this.state === PHB_PENDING) {
              // 添加到微任务
              queueMicrotask(() => {
                if (this.state === PHB_REJECTEDreturn;
                this.value = value;
                this.state = PHB_FULFILLED//修改状态为已完成(fulfilled)
                this.onFulfilled.forEach(item => {
                  item(this.value);
                });
              }, 0);
            }
          };
          // 失败回调
          let reject = reason => {
            if (this.state === PHB_PENDING) {
              // 添加到微任务
              queueMicrotask(() => {
                if (this.state === PHB_FULFILLEDreturn;
                this.value = reason;
                this.state = PHB_REJECTED//修改状态为已拒绝(rejected)
                this.onRejected.forEach(item => {
                  item(this.value);
                });
              }, 0);
            }
          };

图片.png
这个时候我们抛出一个问题,模拟请求2秒后再去去调用phbPromise.then,这个时候还会触发回调吗?
答:不会,这个时候微任务里面的resolve早已经回调了。

 let phbPromise = new PHBPromise((resolve, reject) => {
        resolve('成功');
      });
      // 调用.then方法
      phbPromise.then(
        res => {
          console.log(res);
        },
        err => {
          console.log(err);
        }
      );
      //调用.then还能触发resolve吗?
      setTimeout(function () {
        phbPromise.then(
          res => {
            console.log(res);
          },
          err => {
            console.log(err);
          }
        );
      }, 2000);

then方法bug解决方案

根据状态this.state判断,如果this.state已经是fulfilled或者rejected状态了,说明已经执行过resolve,这个时候我们可以对传入的函数直接调用。

  then(onfulfilled, onrejected) {
          if (this.state === PHB_FULFILLED) {
            onfulfilled(this.value);
          }
          if (this.state === PHB_REJECTED) {
            onrejected(this.value);
          }
          if (this.state === PHB_PENDING) {
            this.onFulfilled.push(onfulfilled);
            this.onRejected.push(onrejected);
          }
      }

图片.png
新需求,增加链式调用then,也就是说,每个then方法都要返回一个新的Promise对象,这样我们的then方法才能不断的链式调用

     phbPromise
        .then(
          res => {
            console.log(res);
            return '第一个then得到成功的结果';
          },
          err => {
            console.log(err);
            return '第一个then得到失败的结果';
          }
        )
        .then(
          res1 => {
            console.log(res1);
          },
          err2 => {
            console.log(err2);
          }
        );

then方法bug解决方案

1.想要链式调用then就必须要 new 一个新的实例对象
2.考虑到所有出错的情况所以都使用try/catch 包裹
3.重点是pending状态下(等待)this.onFulfilled.push一个箭头函数

  then(onfulfilled, onrejected) {
          // new一个新的实例对象,方便链式调用
          return new PHBPromise((resolve, reject) => {
            // 状态为已完成(fulfilled)
            if (this.state === PHB_FULFILLED) {
              try {
                this.value = onfulfilled(this.value);
                resolve(this.value);
              } catch (error) {
                reject(this.value);
              }
            }
            //状态为已拒绝(rejected)
            if (this.state === PHB_REJECTED) {
              try {
                this.value = onrejected(this.value);
                console.log(this.value);
                resolve(this.value);
              } catch (error) {
                reject(this.value);
              }
            }
            //初始化状态  pending(等待)
            if (this.state === PHB_PENDING) {
              this.onFulfilled.push(() => {
                try {
                  this.value = onfulfilled(this.value);
                  resolve(this.value);
                } catch (error) {
                  reject(this.value);
                }
              });

              this.onRejected.push(() => {
                try {
                  this.value = onrejected(this.value);
                  resolve(this.value);
                } catch (error) {
                  reject(this.value);
                }
              });
            }
          });
        }
 phbPromise
        .then(
          res => {
            console.log(res);
            return 'then成功回调1';
          },
          err => {
            console.log(err);
            return 'then失败回调1';
          }
        )
        .then(
          res1 => {
            console.log(res1);
            return 'then成功回调2';
          },
          err1 => {
            console.log(err1);
            return 'then失败回调2';
          }
        )
        .then(
          res2 => {
            console.log(res2);
          },
          err2 => {
            console.log(err2);
          }
        );

图片.png
抛出一个需求:让then方法可以只传递onfulfilled函数,可以通过catch接收失败的回调

then方法bug解决方案

1.当调用then(onfulfilled),onrejected没有值的情况下,默认给个函数返回一个异常
2.onfulfilled没有值的情况下,默认给个一个函数,返回传入的参数,为catch做铺垫

          // catch 只传入失败回调  onfulfille没有的话默认给个函数
          onfulfilled = onfulfilled || (value => {return value; });
          //  then方法可以只传入成功回调 当onrejected没传的话默认给个函数抛出异常
          onrejected = onrejected || (value => { throw this.value;});

最终完整版 then

 then(onfulfilled, onrejected) {
       
          // catch 只传入失败回调  onfulfille没有的话默认给个函数
          onfulfilled = onfulfilled || (value => {return value; });
          //  then方法可以只传入成功回调 当onrejected没传的话默认给个函数抛出异常
          onrejected = onrejected || (value => { throw this.value;});


          // new一个新的实例对象,方便链式调用
          return new PHBPromise((resolve, reject) => {
            // 状态为已完成(fulfilled)
            if (this.state === PHB_FULFILLED) {
              try {
                this.value = onfulfilled(this.value);
                resolve(this.value);
              } catch (error) {
                reject(this.value);
              }
            }
            //状态为已拒绝(rejected)
            if (this.state === PHB_REJECTED) {
              try {
                this.value = onrejected(this.value);
                resolve(this.value);
              } catch (error) {
                reject(this.value);
              }
            }
            //初始化状态  pending(等待)
            if (this.state === PHB_PENDING) {
              this.onFulfilled.push(() => {
                try {
                  this.value = onfulfilled(this.value);
                  resolve(this.value);
                } catch (error) {
                  reject(this.value);
                }
              });

              this.onRejected.push(() => {
                try {
                  this.value = onrejected(this.value);
                  resolve(this.value);
                } catch (error) {
                  reject(this.value);
                }
              });
            }
          });
        }

catch

catch() 方法返回一个Promise (en-US),并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。
只需要去调用then方法,传入onrejected

   catch(onrejected) {
          return this.then(undefined, onrejected);
        }
      }
    let phbPromise = new PHBPromise((resolve, reject) => {
        // resolve('成功');
        reject('失败');
      });
      phbPromise
        .then(res => {
          console.log(res);
          return 'then成功回调1';
        })
        .catch(err => {
          console.log(err);
          return '失败1';
        })
        .then(
          res1 => {
            console.log(res1);
          },
          err2 => {
            console.lgo(err2);
          }
        );

图片.png

finally

finally() 方法返回一个 Promise。在 promise 结束时,无论结果是 fulfilled 或者是 rejected,都会执行指定的回调函数

finally(onFinally) {
     this.then(onFinally, onFinally);
}
 let phbPromise = new PHBPromise((resolve, reject) => {
        // resolve('成功');
        reject('失败');
      });
      phbPromise
        .then(
          res1 => {
            console.log(res1);
          },
          err2 => {
            console.log(err2);
          }
        )
        .finally(function () {
          console.log('finally执行了');
        });

图片.png

Promise.all(iterable)

1.接受一个[可迭代]对象,存储多个Promise实例
2.返回一个新的 promise 对象,等到所有的 promise 对象都成功或失败,去执行resolverejeck
3.一旦有任意一个 里面的 promise 对象失败则立即以该 promise 对象失败的理由来拒绝这个新的 promise

 static all(iterable) {
          return new PHBPromise((resolve, reject) => {
            let value = [];//用于保存成功数据
            iterable.forEach(item => {
              item.then(
                res => {
                  value.push(res); //成功就保存到数组
                  if (value.length === iterable.length) {
                    //全部执行完成就去调用resolve
                    resolve(value);
                  }
                },
                err => {
                  reject(err); //一个失败直接调用reject
                }
              );
            });
          });
        }
      }
   let p1 = new PHBPromise((resolve, reject) => {
        resolve('成功1');
      });
      let p2 = new PHBPromise((resolve, reject) => {
        resolve('成功2');
      });
      let p3 = new PHBPromise((resolve, reject) => {
        resolve('成功3');
      });
      PHBPromise.all([p1, p2, p3])
        .then(res => {
          console.log(res);
        })
        .catch(err => {
          console.log(err);
        });

图片.png

Promise.allSettled(iterable)

1.返回一个在所有给定的 promise 都已经fulfilledrejected后的 promise,并带有一个对象数组,每个对象表示对应的 promise 结果
2.通俗点来说就是不管成功还是失败都会把状态结果保存返回

     static allSettled(iterable) {
          return new PHBPromise(resolve => {
            let value = [];
            //allSettled只会执行成功回调
            iterable.forEach(item => {
              item.then(
                res => {
                  value.push({
                    status'fulfilled'//保存状态,和结果
                    value: res,
                  });
                  if (value.length === iterable.length) {
                    resolve(value);
                  }
                },
                err => {
                  value.push({
                    status'rejected'//保存状态,和结果
                    value: err,
                  });
                  if (value.length === iterable.length) {
         
                    resolve(value);
                  }
                }
              );
            });
          });
        }
      let p1 = new PHBPromise((resolve, reject) => {
        resolve('成功1');
      });
      let p2 = new PHBPromise((resolve, reject) => {
        // resolve('成功2');
        reject('失败');
      });
      let p3 = new PHBPromise((resolve, reject) => {
        resolve('成功3');
      });
      PHBPromise.allSettled([p1, p2, p3]).then(res => {
        console.log(res);
      });

图片.png

Promise.any(iterable)

1.单个拒绝状态不会调用rejeck,所以说new Peomise只需要传递resolve,如果所有状态都是拒绝,才会调用resolve抛出异常
2.只要有一个 promise 兑现了,那么此方法就会提前结束,而不会继续等待其他的 promise 全部敲定。
3.全部是拒绝状态,并且它的拒因会是一个 AggregateError 实例,这是 Error 的子类,用于把单一的错误集合在一起。

       static any(iterable) {
          let isResolve = false//用于判断一个成功回调执行后其他不会执行
          let index = 0;
          return new PHBPromise(resolve => {
            iterable.forEach(item => {
              item.then(
                res => {
                  if (isResolve) return//如果为true   说明已经执行过resolve  后面的就不需要继续执行
                  resolve(res);
                  isResolve = true;
                },
                err => {
                  index++;
                  if (iterable.length === index) {
                    // AggregateError 把单一的错误集合在一起
                    resolve(new AggregateError('''No Promise in Promise.any was resolved'));
                  }
                }
              );
            });
          });
        }
    let p1 = new PHBPromise((resolve, reject) => {
        // resolve('成功1');
        reject('失败1');
      });
      let p2 = new PHBPromise((resolve, reject) => {
        resolve('成功2');
        // reject('失败1');
      });
      let p3 = new PHBPromise((resolve, reject) => {
        reject('失败1');
        // resolve('成功3');
      });
      PHBPromise.any([p1, p2, p3]).then(res => {
        console.log(res);
      });

图片.png

Promise.race(iterable)

1.接收一个可迭代对象,类似Arrayrace 函数返回一个 Promise
2.一旦迭代器中的某个promise解决或拒绝,返回的 promise就会直接resolvereject

     static race(iterable) {
          let isCallBack = false//用于判断一个成功回调执行后其他不会执行
          return new PHBPromise((resolve, reject) => {
            iterable.forEach(item => {
              item.then(
                res => {
                  if (isCallBack) return// 为true 直接返回
                  resolve(res);
                  isCallBack = true;
                },
                err => {
                  if (isCallBack) return// 为true 直接返回
                  reject(err);
                  isCallBack = true;
                }
              );
            });
          });
        }
      let p1 = new PHBPromise((resolve, reject) => {
        setTimeout(() => {
          reject('失败1');
        }, 4000);
      });

      let p2 = new PHBPromise((resolve, reject) => {
        setTimeout(() => {
          resolve('成功2');
        }, 2000);
      });
      let p3 = new PHBPromise((resolve, reject) => {
        setTimeout(function () {
          reject('失败2');
        }, 3000);
      });

     PHBPromise.race([p1, p2, p3]).then(
        res => {
          console.log(res);
        },
        err => {
          console.log(err);
        }
      );

图片.png

Promise.resolve(value)

       static resolve(value) {
          return new PHBPromise(resolve => {
            resolve(value);
          });
        }
      PHBPromise.resolve('成功1')
        .then(res => {
          console.log(res);
          return '成功2';
        })
        .then(res => {
          console.log(res);
        });

图片.png

Promise.reject(reason)

     static reject(value) {
          return new PHBPromise((undefined, reject) => {
            reject(value);
          });
        }
       PHBPromise.reject('失败1')
        .then(res => {
          console.log(res);
        })
        .catch(err => {
          console.log(err);
        });

图片.png

PHBPromise最终代码

      // “Promise的三种状态: pending、fulfilled、rejected(等待,已完成,已拒绝)
      const PHB_PENDING = 'pending';
      const PHB_FULFILLED = 'fulfilled';
      const PHB_REJECTED = 'rejected';
      class PHBPromise {
        constructor(executor) {
          this.state = PHB_PENDING// 初始化状态  pending(等待)
          this.value = null//成功的结果或者失败的结果
          this.onFulfilled = []; //成功的回调
          this.onRejected = []; //失败的回调
          // 成功回调
          let resolve = value => {
            if (this.state === PHB_PENDING) {
              // 添加到微任务
              queueMicrotask(() => {
                if (this.state === PHB_REJECTEDreturn;
                this.value = value;
                this.state = PHB_FULFILLED//修改状态为已完成(fulfilled)
                this.onFulfilled.forEach(item => {
                  item(this.value);
                });
              }, 0);
            }
          };
          // 失败回调
          let reject = reason => {
            if (this.state === PHB_PENDING) {
              // 添加到微任务
              queueMicrotask(() => {
                if (this.state === PHB_FULFILLEDreturn;
                this.value = reason;
                this.state = PHB_REJECTED//修改状态为已拒绝(rejected)
                this.onRejected.forEach(item => {
                  item(this.value);
                });
              }, 0);
            }
          };
          // 执行接收的函数并传入函数参数,executor也会可能存在异常,因此通过try/catch来捕获一下异常情况
          try {
            executor(resolve, reject);
          } catch (error) {
            reject(error);
          }
        }
        then(onfulfilled, onrejected) {
        
           // catch 只传入失败回调  onfulfille没有的话默认给个函数
          onfulfilled = onfulfilled || (value => {return value; });
          
          //  then方法可以只传入成功回调 当onrejected没传的话默认给个函数抛出异常
          onrejected = onrejected || (value => { throw this.value;});
          
          // new一个新的实例对象,方便链式调用
          return new PHBPromise((resolve, reject) => {
            // 状态为已完成(fulfilled)
            if (this.state === PHB_FULFILLED) {
              try {
                this.value = onfulfilled(this.value);
                resolve(this.value);
              } catch (error) {
                reject(this.value);
              }
            }
            //状态为已拒绝(rejected)
            if (this.state === PHB_REJECTED) {
              try {
                this.value = onrejected(this.value);
                resolve(this.value);
              } catch (error) {
                reject(this.value);
              }
            }
            //初始化状态  pending(等待)
            if (this.state === PHB_PENDING) {
              this.onFulfilled.push(() => {
                try {
                  this.value = onfulfilled(this.value);
                  resolve(this.value);
                } catch (error) {
                  reject(this.value);
                }
              });

              this.onRejected.push(() => {
                try {
                  this.value = onrejected(this.value);
                  resolve(this.value);
                } catch (error) {
                  reject(this.value);
                }
              });
            }
          });
        }
        catch(onrejected) {
          return this.then(undefined, onrejected);
        }
        finally(onFinally) {
          this.then(onFinally, onFinally);
        }
        static all(iterable) {
          return new PHBPromise((resolve, reject) => {
            let value = []; //用于保存成功数据
            iterable.forEach(item => {
              item.then(
                res => {
                  value.push(res); //成功就保存到数组
                  if (value.length === iterable.length) {
                    //全部执行完成就去调用resolve
                    resolve(value);
                  }
                },
                err => {
                  reject(err); //一个失败直接调用reject
                }
              );
            });
          });
        }
        static allSettled(iterable) {
          return new PHBPromise(resolve => {
            let value = [];
            //allSettled只会执行成功回调
            iterable.forEach(item => {
              item.then(
                res => {
                  value.push({
                    status'fulfilled'//保存状态,和结果
                    value: res,
                  });
                  if (value.length === iterable.length) {
                    resolve(value);
                  }
                },
                err => {
                  value.push({
                    status'rejected'//保存状态,和结果
                    value: err,
                  });
                  if (value.length === iterable.length) {
                    resolve(err);
                  }
                }
              );
            });
          });
        }
        static any(iterable) {
          let isResolve = false//用于判断一个成功回调执行后其他不会执行
          let index = 0;
          return new PHBPromise(resolve => {
            iterable.forEach(item => {
              item.then(
                res => {
                  if (isResolve) return//如果为true   说明已经执行过resolve  后面的就不需要继续执行
                  resolve(res);
                  isResolve = true;
                },
                err => {
                  index++;
                  if (iterable.length === index) {
                    // AggregateError 把单一的错误集合在一起
                    resolve(new AggregateError('''No Promise in Promise.any was resolved'));
                  }
                }
              );
            });
          });
        }
        static race(iterable) {
          let isCallBack = false//用于判断一个成功回调执行后其他不会执行
          return new PHBPromise((resolve, reject) => {
            iterable.forEach(item => {
              item.then(
                res => {
                  if (isCallBack) return// 为true 直接返回
                  resolve(res);
                  isCallBack = true;
                },
                err => {
                  if (isCallBack) return// 为true 直接返回
                  reject(err);
                  isCallBack = true;
                }
              );
            });
          });
        }
        static resolve(value) {
          return new PHBPromise(resolve => {
            resolve(value);
          });
        }
        static reject(value) {
          return new PHBPromise((undefined, reject) => {
            reject(value);
          });
        }
      }