1. 我是皮皮虾首页
  2. 编程开发
  3. 前端

前端学习记录之三:手写Promise源码

一、初始化版本

  • 1.Promise 就是一个类 在执行这个类的时候 需要传递一个(回调函数)执行器进去 执行器立即执行
  • 2.Promise有三种状态 fulfilled rejected pending
  • 3.pending -> fulfilled rejected
  • resolve和reject就是用来更改状态的
  • 状态一旦确定则不可更改
  • 4.then方法内部做的事情就是判断状态,如果状态成功则执行成功的回调 失败则执行失败的回调 是被定义在原型对象中的
  • 5.then成功之后有一个参数,表示成功后的值,失败后有一个失败原因
// Promise有三种状态  fulfilled  rejected  pending  
const FULFILLED = 'fulfulled'
const REJECT = 'reject'
const PENDING = 'pending'
// Promise 就是一个类
class myPromise{
    // 在执行这个类的时候  需要传递一个(回调函数)执行器进去
    constructor(executor) {
        // 执行器立即执行
        executor(this.resolve, this.reject)
    }
    status = PENDING
    successCallback = undefined
    failCallback = undefined
    value = undefined
    reason = undefined
    resolve = (value => {
        // 状态一旦确定则不可更改
        if(this.status !== PENDING) return
        // resolve和reject就是用来更改状态的
        this.status = FULFILLED
        this.value = value
    })
    reject = (reason => {
        // 状态一旦确定则不可更改
        if(this.status !== PENDING) return
        // resolve和reject就是用来更改状态的
        this.status = REJECT
        this.reason = reason
    })
    then = ((sucessCallback, failCallback) => {
        // then方法内部做的事情就是判断状态,被定义在原型对象中的
        if(this.status === FULFILLED) {
            // 状态成功则执行成功的回调,传入成功后的值
            sucessCallback(this.value)
        } else if (this.status === REJECT) {
            // 状态失败则执行失败的回调,传入失败后的原因
            failCallback(this.reason)
        } else {
            // 等待  将成功回调和失败回调存储起来
            this.successCallback = sucessCallback
            this.failCallback = failCallback
        }
    })
}
// 测试
new Promise((resolve, reject) => {
    // resolve(7)
    reject('cuole')
}).then((value)=>{
    console.log(value)
},reason=>{
    console.log(reason)
})

二:then方法

1.多次调用添加多个处理函数

  • 分同步的情况和异步的情况,同步的情况不需要处理   
  •  异步的情况下每一个回调函数的状态都应该存储起来  需要保证前一个函数结束后执行另一个函数  等到状态编程成功或者失败的时候再依次调用

2.链式调用

  • then方法的链式调用:每个then方法返回一个promise对象 
  • 后面then方法的回调函数拿到值是上一个then方法的回调函数的返回值   
  • 判断返回值x是普通值还是promise对象     

 普通值: 直接调用resolve     

 promise对象: 查看promise对象返回的结果      根据promise对象返回的结果,决定调用resolve还是reject

3.识别Promise对象自返回

  • 在then方法的回调函数中,不能返回当前then方法返回的promise对象  否则会造成promise的循环调用  会报错   
  •  需要判断回调函数跟当前的promise是不是相等  如果相等直接reject

4.then方法的参数变成可选参数

  • 如果then方法没有传递参数,那么就补充一个函数进来

5.捕获错误以及then链式调用其他状态代码补充

  • try-catch捕获当前Promise对象 
  • 捕获then链式调用中的回调函数的错误
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败

class MyPromise {
  constructor (executor) {
    try {
      executor(this.resolve, this.reject)
    } catch (e) {
      this.reject(e);
    }
  }
  // promsie 状态 
  status = PENDING;
  // 成功之后的值
  value = undefined;
  // 失败后的原因
  reason = undefined;
  // 成功回调
  successCallback = [];
  // 失败回调
  failCallback = [];

  resolve = value => {
    // 如果状态不是等待 阻止程序向下执行
    if (this.status !== PENDING) return;
    // 将状态更改为成功
    this.status = FULFILLED;
    // 保存成功之后的值
    this.value = value;
    // 判断成功回调是否存在 如果存在 调用
    // this.successCallback && this.successCallback(this.value);
    while(this.successCallback.length) this.successCallback.shift()()
  }
  reject = reason => {
    // 如果状态不是等待 阻止程序向下执行
    if (this.status !== PENDING) return;
    // 将状态更改为失败
    this.status = REJECTED;
    // 保存失败后的原因
    this.reason = reason;
    // 判断失败回调是否存在 如果存在 调用
    // this.failCallback && this.failCallback(this.reason);
    while(this.failCallback.length) this.failCallback.shift()()
  }
  then (successCallback, failCallback) {
    // 参数可选
    successCallback = successCallback ? successCallback : value => value;
    // 参数可选
    failCallback = failCallback ? failCallback: reason => { throw reason };
    let promsie2 = new MyPromise((resolve, reject) => {
      // 判断状态
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            let x = successCallback(this.value);
            // 判断 x 的值是普通值还是promise对象
            // 如果是普通值 直接调用resolve 
            // 如果是promise对象 查看promsie对象返回的结果 
            // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
            resolvePromise(promsie2, x, resolve, reject)
          }catch (e) {
            reject(e);
          }
        }, 0)
      }else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = failCallback(this.reason);
            // 判断 x 的值是普通值还是promise对象
            // 如果是普通值 直接调用resolve 
            // 如果是promise对象 查看promsie对象返回的结果 
            // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
            resolvePromise(promsie2, x, resolve, reject)
          }catch (e) {
            reject(e);
          }
        }, 0)
      } else {
        // 等待
        // 将成功回调和失败回调存储起来
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              let x = successCallback(this.value);
              // 判断 x 的值是普通值还是promise对象
              // 如果是普通值 直接调用resolve 
              // 如果是promise对象 查看promsie对象返回的结果 
              // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
              resolvePromise(promsie2, x, resolve, reject)
            }catch (e) {
              reject(e);
            }
          }, 0)
        });
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let x = failCallback(this.reason);
              // 判断 x 的值是普通值还是promise对象
              // 如果是普通值 直接调用resolve 
              // 如果是promise对象 查看promsie对象返回的结果 
              // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
              resolvePromise(promsie2, x, resolve, reject)
            }catch (e) {
              reject(e);
            }
          }, 0)
        });
      }
    });
    return promsie2;
  }
}

function resolvePromise (promsie2, x, resolve, reject) {
  if (promsie2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (x instanceof MyPromise) {
    // promise 对象
    // x.then(value => resolve(value), reason => reject(reason));
    x.then(resolve, reject);
  } else {
    // 普通值
    resolve(x);
  }
}

三、最终版本

1.Promise.all方法的实现 

解决异步并发问题  以调用的顺序获取结果

  • 静态方法,接受数组作为参数    
  • 返回的是一个Promise对象    
  • 循环数组判断数组当前值是普通值 or Promise对象,普通值直接输出  Promise对象需要先执行 执行后的返回的结果放到数组中  最后输出一个结果数组    
  • 注意异步操作情况,需要等待异步操作完成之后才能resolve  使用index记录返回数组的长度,如果index与数组长度不一致则等待一致后返回

2.Promise.resolve方法的实现  

将给定值转换成promise对象   返回值是一个promise对象  返回的promise中包裹着给定值

  • 接受的值判断当前值是普通值(用promise对象包裹) or Promise对象(原封不动返回)

3.finally方法的实现

1.无论promise对象成功或者失败 回调函数始终都会被执行    

2.finally方法后面的then方法可以拿到当前promise对象返回的结果

实现:

  • 需要定义在promise的原型链中  接受一个回调函数作为参数 使用this.then方法来获取当前promise对象状态  成功和失败回调函数中调用回调函数    
  • finally方法需要返回一个promise对象  需要在then方法中拿到成功的值或者失败结果 return 或者 throw的方式传递出去    
  • 注意:finally方法如果返回的是一个异步执行的函数 此时finally方法的then方法可能返回值还是上一个的结果 需要等待            此时需要借助promise的resolve方法:接受的值判断当前值是普通值(用promise对象包裹) or Promise对象(原封不动返回)

4..catch方法的实现

当前promise最终状态为失败的情况

  • 在catch方法的内部去调用then方法 成功回调传入undefined 失败的传入回调函数
// Promise有三种状态  fulfilled  rejected  pending  
const fulfilled = 'fulfilled'
const rejected = 'rejected'
const pending = 'pending'
class myPromise {
    constructor (executor) {
        // 执行器立即执行
        // 捕获执行器错误
        try {
            executor(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }        
    }
    // promise状态
    status = pending
    // 成功的值
    _value = undefined
    // 失败的原因
    _reason = undefined
    // 成功回调 多个 每个回调函数的状态都应该存储起来
    sucessCallback = []
    // 失败回调
    failCallback = []
    // 箭头函数是考虑this指向
    resolve = (value)=> {
        // 状态一旦确定则不可更改
        if(this.status!==pending) return
        // resolve和reject就是用来更改状态的
        this.status = fulfilled
        this._value = value
        // 成功则执行成功的回调
        // this.sucessCallback && this.sucessCallback(this._value)
        while (this.sucessCallback.length) this.sucessCallback.shift()()
    }
    reject = (reason)=> {
        if(this.status!==pending) return
        this.status = rejected
        this._reason = reason
        // this.failCallback && this.failCallback(this._reason)
        while (this.failCallback.length) this.failCallback.shift()()
    }
    // 判断状态,如果状态成功则执行成功的回调 失败则执行失败的回调
    then = (sucessCallback, failCallback) => {
        sucessCallback = sucessCallback ? sucessCallback : value => value
        failCallback = failCallback ? failCallback : reason => {throw reason}
        // then方法的回调函数拿到值是上一个then方法的回调函数的返回值
        let promise2 = new myPromise((resolve, reject) => {
            // 判断状态
            if(this.status === fulfilled) {
                setTimeout(() => {
                    try {
                        let x = sucessCallback(this._value)
                        // 判断 x 的值是普通值还是promise对象
                        // 如果是普通值 直接调用resolve 
                        // 如果是promise对象 查看promsie对象返回的结果 
                        // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
                        resolvePromise(promise2, x, resolve, reject)
                    }catch (e) {
                    reject(e);
                    }
                }, 0)
                // // 为了把promise执行完成之后再执行里面的代码
                // setTimeout(() => {
                //      // 成功之后有一个参数
                //     let x = sucessCallback(this._value)
                //     // resolve(x)
                //     // 判断返回值类型,并做相应处理
                //     resolvePromise(promise2, x, resolve, reject)
                // }, 0);              
            } else if (this.status === rejected) {
                setTimeout(() => {
                    try {
                      let x = failCallback(this._reason);
                      // 判断 x 的值是普通值还是promise对象
                      // 如果是普通值 直接调用resolve 
                      // 如果是promise对象 查看promsie对象返回的结果 
                      // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
                      resolvePromise(promise2, x, resolve, reject)
                    }catch (e) {
                      reject(e);
                    }
                  }, 0)
            } else {
                // 异步逻辑  等待
                // 将成功回调和失败回调存储起来
                // this.sucessCallback.push(sucessCallback)
                // this.failCallback.push(failCallback)
                this.sucessCallback.push(() => {
                    setTimeout(() => {
                      try {
                        let x = sucessCallback(this._value);
                        resolvePromise(promise2, x, resolve, reject)
                      }catch (e) {
                        reject(e);
                      }
                    }, 0)
                  })
                  this.failCallback.push(() => {
                    setTimeout(() => {
                      try {
                        let x = failCallback(this._reason)
                        resolvePromise(promise2, x, resolve, reject)
                      }catch (e) {
                        reject(e);
                      }
                    }, 0)
                  })
            }
        })
        return promise2
    }
    static all (arr) {
        let res = []
        let index = 0
        return new myPromise((resolve, reject)=>{
            function addData(key, value) {
                res[key] = value
                index++
                if(index === arr.length) resolve(res)  
            }
            for(let i=0;i<arr.length;i++){
                let current = arr[i]
                if(current instanceof myPromise) {
                    // Promise对象
                    current.then(value=>{
                        addData(i, value)
                    },reason=>{reject(reason)})
                } else {
                    // 普通值 直接push进去数组
                    addData(i, arr[i])
                }
            }       
        })
    }
    static resolve (val) {
        if(val instanceof myPromise) return val
        return new myPromise(resolve=>resolve(val))
    }
    finally (callback){
        return this.then((val)=>{
           return myPromise.resolve(callback()).then(()=> val)
            // callback(val)
            // return val
        },reason=>{
          return  myPromise.resolve(callback()).then(()=> {throw reason})
            // callback(reason)
            // return reason
        })
        // return new myPromise(resolve=>resolve())
    }
    catch (callback) {
        // 1.在catch方法的内部去调用then方法 成功回调传入undefined 失败的传入回调函数
        // return this.then(undefined, callback)
        return this.then(()=>{
            return undefined
        }, reason=>{
            callback(reason)
        })
    }
}
function resolvePromise (promise2, x, resolve, reject) {
    if(promise2 === x) {
        return x.reject(new TypeError('循环调用了'))
    }
    if(x instanceof myPromise) {
        // 根据promise对象返回的结果,决定调用resolve还是reject
        // x.then(value => resolve(value), reason => reject(reason))
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}

原创文章,作者:一苇,如若转载,请注明出处:https://wsppx.cn/895/%e7%bd%91%e7%bb%9c%e5%bc%80%e5%8f%91/%e5%89%8d%e7%ab%af/

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注