写Promise

100 阅读6分钟

初始化promise

定义三个状态常量:

var PENGDING = 'PENDING';
var RESOLVED = 'RESOLVED';
var REJECTED = 'REJECTED';

构造promise对象,执行传入函数:

当初始化的时候,初始化promise对象的status为PENGING进行中

定义一个成功回调函数数组和一个失败函数的回调数组。

data属性为promise对象的成功时候的返回值

err属性是promise对象失败时候的返回值。

当promise初始化的时候就会同步执行传入函数fn,fn传入参数为定义好的resolve和reject函数.

当执行fn过程中,如果调用了resolve,就要更改promise对象的状态为RESOLVED,并且设置成功的值data,然后调用所有已经保存好的成功的回调函数,调用了reject函数同理。

fn执行中可能会报错,用try..catch进行捕获,用reject函数进行错误处理。

 constructor(fn) {
        this.status=PENGDING;
        this.successCallbacks=[];
        this.failCallbacks=[];
        this.data=undefined;
        this.err=undefined;
        let resolve=(data)=>{
            if(this.status===PENGDING){
                this.status=RESOLVED;
                this.data=data;
                this.successCallbacks.forEach(successCallback=>{
                    successCallback()
                })
            }
        }
        let reject=(err)=>{
            if(this.status===PENGDING){
                this.status=REJECTED;
                this.err=err;
                this.failCallbacks.forEach(failCallback=>{
                    failCallback()
                })
            }

        }
        try{
            fn(resolve,reject);
        }catch(e){
            reject(e);
        }
    }

then的实现:

then的两个函数,成功的回调和失败的回调都是可选的参数:

successFn= typeof successFn === 'function' ? successFn : data=> data;
    failFn= typeof failFn === 'function' ? failFn : err=>{throw err};

为了实现then的链式调用,我们定义一个promise2,将then函数的处理结果保存在promise2中进行返回,就可以实现promise的链式调用。

then函数的执行包括同步和异步两种,当代码顺序执行到then函数的时候,如果当前的promise已经执行完成,并且状态为RESOLVED或者REJECTED的时候,就可以调用同步的成功或者失败回调。

为什么成功和失败回调要进行异步处理?因为要拿到promise2对象。

x为回调函数处理结果,judgmentResults会处理x与promise2的关系,得到正确的promise2对象。

then(successFn,failFn){
    successFn= typeof successFn === 'function' ? successFn : data=> data;
    failFn= typeof failFn === 'function' ? failFn : err=>{throw err};
    var promise2=new Promise((resolve,reject)=>{
                //同步
                if(this.status===RESOLVED){
                    setTimeout(()=>{
                        try{
                            var x=successFn(this.data);
                            this.judgmentResults(promise2,x,resolve,reject);
                        }catch(e){
                            reject(e);
                        }
                    },0)
                }

                if(this.status===REJECTED){
                    setTimeout(()=>{
                        try{
                            var x=failFn(this.err);
                            this.judgmentResults(promise2,x,resolve,reject);
                        }catch(e){
                            reject(e);
                        }
                    },0)
                }
                //异步
                if(this.status===PENGDING){
                    this.successCallbacks.push(()=>{
                        setTimeout(()=>{
                            try{
                                var x=successFn(this.data);
                                judgmentResults(promise2,x,resolve,reject);
                            }catch(e){
                                reject(e)
                            }
                        },0)
                    });
                    this.failCallbacks.push(()=>{
                            setTimeout(()=>{
                                try{
                                    var x=failFn(this.err);
                                    judgmentResults(promise2,x,resolve,reject);
                                }catch(e){
                                    reject(e);
                                }
                            },0);
                    });
                }

    })
    return promise2;
}

judgmentResults实现:

x与promise2不能是同一个value,原因如下:

var promise=new Promise((resolve,reject)=>{
    resolve("3333")
})
var promise2=promise.then(data=>{
    return promise2;
})
promise2.then(data=>{
    console.log(data)
})

x可能是对象或者是函数,当不是其中一个的时候,就会调用reject处理。

获取对象或者函数的then属性,有可能会报错,报错的话就reject处理

然后判断then属性是不是函数,如果是就可以判定是promise对象,否则就是普通数据

如何then是一个函数,也就是一个peomise对象,调用then函数,在then的成功会回调中,很可能成功回调的参数也是一个promise对象,要继续进行judgmentResults函数回调处理,直到回调参数不是一个promise对象为止。

在then函数的失败回调中处理promise2的reject函数。

const  judgmentResults=(promise2,x,resolve,reject)=>{
    var called;
    if(promise2===x){
        return reject(new TypeError("不能返回类型相同的promise"));
    }
    if(typeof x==="object" && x!==null||typeof x==="function"){
        try {
            let then=x.then;
            //如果then是一个funciton,则可以认为x是一个promise
            if(typeof then==='function'){
                then.call(x,y=>{
                    if(called){
                        return;
                    }
                    called=true;
                    judgmentResults(promise2,y,resolve,reject);
                },r=>{
                    if(called){
                        return;
                    }
                    called=true;
                    reject(r);
                })
            }else{
                if(called){
                    return ;
                }
                called=true;
                resolve(x);
            }
        }catch(e){
            if(called){
                return ;
            }
            called=true;
            reject(e);
        }
    }else{
        if(called){
            return ;
        }
        called=true;
        resolve(x);
    }
}

检验手写promise是否能够通过所有测试

npm i promises-aplus-tests -g

然后运行下面命令:

App.js为源代码文件

promises-aplus-tests App.js

promise完整代码:

// 判断变量否为function
  const isFunction = variable => typeof variable === 'function'
  // 定义Promise的三种状态常量
  const PENDING = 'PENDING'
  const FULFILLED = 'FULFILLED'
  const REJECTED = 'REJECTED'

  class MyPromise {
    constructor (handle) {
      if (!isFunction(handle)) {
        throw new Error('MyPromise must accept a function as a parameter')
      }
      // 添加状态
      this._status = PENDING
      // 添加状态
      this._value = undefined
      // 添加成功回调函数队列
      this._fulfilledQueues = []
      // 添加失败回调函数队列
      this._rejectedQueues = []
      // 执行handle
      try {
        handle(this._resolve.bind(this), this._reject.bind(this)) 
      } catch (err) {
        this._reject(err)
      }
    }
    // 添加resovle时执行的函数
    _resolve (val) {
      const run = () => {
        if (this._status !== PENDING) return
        this._status = FULFILLED
        // 依次执行成功队列中的函数,并清空队列
        const runFulfilled = (value) => {
          let cb;
          while (cb = this._fulfilledQueues.shift()) {
            cb(value)
          }
        }
        // 依次执行失败队列中的函数,并清空队列
        const runRejected = (error) => {
          let cb;
          while (cb = this._rejectedQueues.shift()) {
            cb(error)
          }
        }
        /* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后,
          当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态
        */
        if (val instanceof MyPromise) {
          val.then(value => {
            this._value = value
            runFulfilled(value)
          }, err => {
            this._value = err
            runRejected(err)
          })
        } else {
          this._value = val
          runFulfilled(val)
        }
      }
      // 为了支持同步的Promise,这里采用异步调用
      setTimeout(run, 0)
    }
    // 添加reject时执行的函数
    _reject (err) { 
      if (this._status !== PENDING) return
      // 依次执行失败队列中的函数,并清空队列
      const run = () => {
        this._status = REJECTED
        this._value = err
        let cb;
        while (cb = this._rejectedQueues.shift()) {
          cb(err)
        }
      }
      // 为了支持同步的Promise,这里采用异步调用
      setTimeout(run, 0)
    }
    // 添加then方法
    then (onFulfilled, onRejected) {
      const { _value, _status } = this
      // 返回一个新的Promise对象
      return new MyPromise((onFulfilledNext, onRejectedNext) => {
        // 封装一个成功时执行的函数
        let fulfilled = value => {
          try {
            if (!isFunction(onFulfilled)) {
              onFulfilledNext(value)
            } else {
              let res =  onFulfilled(value);
              if (res instanceof MyPromise) {
                // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
                res.then(onFulfilledNext, onRejectedNext)
              } else {
                //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
                onFulfilledNext(res)
              }
            }
          } catch (err) {
            // 如果函数执行出错,新的Promise对象的状态为失败
            onRejectedNext(err)
          }
        }
        // 封装一个失败时执行的函数
        let rejected = error => {
          try {
            if (!isFunction(onRejected)) {
              onRejectedNext(error)
            } else {
                let res = onRejected(error);
                if (res instanceof MyPromise) {
                  // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
                  res.then(onFulfilledNext, onRejectedNext)
                } else {
                  //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
                  onFulfilledNext(res)
                }
            }
          } catch (err) {
            // 如果函数执行出错,新的Promise对象的状态为失败
            onRejectedNext(err)
          }
        }
        switch (_status) {
          // 当状态为pending时,将then方法回调函数加入执行队列等待执行
          case PENDING:
            this._fulfilledQueues.push(fulfilled)
            this._rejectedQueues.push(rejected)
            break
          // 当状态已经改变时,立即执行对应的回调函数
          case FULFILLED:
            fulfilled(_value)
            break
          case REJECTED:
            rejected(_value)
            break
        }
      })
    }
    // 添加catch方法
    catch (onRejected) {
      return this.then(undefined, onRejected)
    }
    // 添加静态resolve方法
    static resolve (value) {
      // 如果参数是MyPromise实例,直接返回这个实例
      if (value instanceof MyPromise) return value
      return new MyPromise(resolve => resolve(value))
    }
    // 添加静态reject方法
    static reject (value) {
      return new MyPromise((resolve ,reject) => reject(value))
    }
    // 添加静态all方法
    static all (list) {
      return new MyPromise((resolve, reject) => {
        /**
         * 返回值的集合
         */
        let values = []
        let count = 0
        for (let [i, p] of list.entries()) {
          // 数组参数如果不是MyPromise实例,先调用MyPromise.resolve
          this.resolve(p).then(res => {
            values[i] = res
            count++
            // 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled
            if (count === list.length) resolve(values)
          }, err => {
            // 有一个被rejected时返回的MyPromise状态就变成rejected
            reject(err)
          })
        }
      })
    }
    // 添加静态race方法
    static race (list) {
      return new MyPromise((resolve, reject) => {
        for (let p of list) {
          // 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变
          this.resolve(p).then(res => {
            resolve(res)
          }, err => {
            reject(err)
          })
        }
      })
    }
    finally (cb) {
      return this.then(
        value  => MyPromise.resolve(cb()).then(() => value),
        reason => MyPromise.resolve(cb()).then(() => { throw reason })
      );
    }
  }