手写Promise,完整实现Promise所有功能

547 阅读5分钟

异步操作包含哪些?

  • fs 文件操作
  • 数据库操作
  • AJAX
  • 定时器

为什么要用Promise?

Prmise支持链式调用,可以解决回调地狱问题

Promise的基本构造?

Promise是一个构造函数,声明的时候需要传入两个函数resolve,reject
    当成功调用resolve(这里还能做一些操作,将会当作返回值,传送给.then(xxx))
    当失败调用reject(这里也能做一些操作,将会当做返回值,传送给.catch(xxx))
promise有三种状态
    pending
    resolved / fullfilled
    rejected
Promise有三个参数
    PromiseState:用来定义状态
    PromiseResult:用来返回结果
    callback:用来存储多次调用then方法的异步操作

Promise的封装方法:

const p = new Promise((resolve,reject) = > {
    setTimeout( () => {
        let count = Math.random() * 100;
        if ( n < 50) {
            resolve('data-success')
        } else {
            reject('data-fail')
        }
    })
})

node自带封装好的primise === util.promisfy(func):传入func即可将func封装为promise

封装ajax

function senAJAX(url) {
    return new Promise((resolve,reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET',url);
        xhr.send();
        //处理结果
        xhr.onreadstatechange = function() {
            if(xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.response)
                } else {
                    reject(xhr.status)
                }
            }
        }
    })
}

当执行器executor内部是同步操作:

let P = Promise((resolve,reject) => {
    //这里是同步任务
    resolve('同步')
});
P.then( value => {
    //这里是异步任务
    console.log(value)
})
// 执行顺序:先执行同步的resolve,返回状态,再执行.then回调

当执行器executor内部是异步操作:

let P = Promise((resolve,reject) => {
    setTimeout( () => {
        resolve('异步')
    },1000)
});
P.then( value => {
    console.log(value)
})
// 模拟正常接口请求,会产生异步请求:执行顺序:  将.then里的方法塞入回调数组内等待状态=>返回异步状态resolve=>按照顺序执行回调.then

链式回调 => 错误捕捉 => 中断链式

let P = Promise((resolve,reject) => {
    setTimeout( () => {
        resolve('异步')
    },1000)
});
P.then( value => {
    console.log(value) // '异步'
    return new Promise((resolve,reject) => {
        resolve('第二次返回')
    })
}).then(value => {
    console.log(value) // '第二次返回'
    // return new Promise(() => {}) // 如果要中断,只有返回pendding状态的promise才能中断
}).then(value => {
    console.log(value) // 'undefined' 因为第二次的回调函数.then并没有返回Promise,就没有返回相应的value    
}).catch(err => {
    console.log(err) // 最后使用一次catch能获取上没每个promise的错误信息
})

手写Promise

手写前的知识储备:

1.Promise构造函数:Promise(executor) {}
    executor:执行器(resolve,reject) => {}
    executor会在Promise内部立即同步调用(同步指按顺序调用)
2.Promise.prototype.then方法:(onResolved,onRejected) =>{}
    Promise.prototype.catch方法:(onRejected) =>{}
3.resolve方法,Promise.resolve是函数方法而不是实例方法
    当传入非promise值的时候,返回一个成功的Promise
    当传入Promise的时候,Promise的状态和值决定resolve的状态和值(套娃)
4.reject方法,Promise.reject是函数的方法而不是实例方法
    不管传入什么,返回都是失败的Promise
5.all方法,Promise.all(arr),成功则放回 所有Promise成功的结果组成的数组,失败则放回第一个失败的Promise返回的error,只要有一个失败就直接失败
6.race方法,Promise.race(arr),第一个返回结果的promise决定返回的状态
class promise {
  //构造方法
  constructor(executor) {
      // 添加属性
    this.PromiseState = 'pending';
    this.PromiseResult = null;

    // 当executor中执行异步操作,then中并没有获取到具体的状态,无法执行,所以要声明一个回调函数,保存then的回调
    this.callback = []; // 可能存在一个promise多次回调.then
    // 保存实例对象的this
    const self = this;
    // executor 获得传入的resolve,reject
    // resolve函数
    function resolve(data) {
      if(self.PromiseState !== 'pending') return;  //增加判断,让状态只能更改一次
      //修改对象状态 promiseState
      self.PromiseState = 'fulfilled'; //resolved
      //返回对象的结果 promiseResult
      self.PromiseResult = data;
      setTimeout(() => {
        // .then是异步操作
        self.callback.forEach(element => {
          element.onResolved(data)
        });
      });
    }
    // reject函数
    function reject(data) {
      if(self.PromiseState !== 'pending') return;
      //修改对象状态 promiseState
      self.PromiseState = 'rejected'; 
      //返回对象的结果 promiseResult
      self.PromiseResult = data;
      setTimeout(() => {
        // .then是异步操作
        self.callback.forEach(element => {
          element.onRejected(data)
        });
      });
      
    }
    try{
      // 同步调用 执行器函数
      executor(resolve,reject);
    }catch(e){
      reject(e)
    }
  }

  then(onResolved,onRejected) {
    let self = this;
    // 异常穿透,多个.then却没有对reject的处理,onRejected为undefined
    if (typeof onRejected !== 'function') {
      onRejected = reason => {
        throw reason
      }
    }
    // 当直接.then,then内部也没有嵌套函数,则onResolved也为undefined,给个默认值
    if (typeof onResolved !== 'function') {
      onResolved = value => value
    }
    return new Promise((resolve,reject) => {
      // 封装callback函数
      function getcallback(type) {
        try {
          let result = type(self.PromiseResult);
          if(result instanceof Promise) {
            //如果是Promise类型的对象
            result.then(v => {
              resolve(v)
            },r => {
              reject(r)
            })
          }else {
            resolve(result)
          }
        } catch (error) {
          reject(error)
        }
      }
      //给then返回Promise,以防发生套娃(在.then函数内继续嵌套Promise)
      if(this.PromiseState === 'fulfilled') {
        setTimeout(() => {
          // .then是异步操作
          getcallback(onResolved)
        });
      }
      if(this.PromiseState === 'rejected') {
        setTimeout(() => {
          // .then是异步操作
          getcallback(onRejected)
        });
      }
      if(this.PromiseState === 'pending') {
        //当executor中有异步操作,状态还未改变,保存回调函数
        this.callback.push({
          onResolved:function(){
            getcallback(onResolved)
            // onResolved(self.PromiseResult)
          },
          onRejected:function(){
            getcallback(onRejected)
            // onRejected(self.PromiseResult)
          }
        });
      }
    })
  }

  catch(onRejected) {
    return this.then(undefined,onRejected)
  }

  static resolve(value) {
    // 返回Promise对象
    return new Promise((resolve,reject) => {
      if(value instanceof Promise) {
        value.then(v => {
          resolve(v)
        },r => {
          reject(r)
        })
      } else {
        // 非Promise,则修改状态,返回内容
        resolve(value)
      }
    })
  }

  // 无论传入什么,都返回失败reject的Promise
  static reject(reason) {
    return new Promise((resolve,reject) => {
      reject(reason)
    })
  }

  // all:所有promise都成功则根据数组序列将结果塞进对应的返回结果中,然后改变状态
  // 当有一个promise先返回错误后,则立马修改状态,并返回当前Promise的结果
  static all(promises){
    return new Promise((resolve,reject) => {
      let count = 0;
      let arr = [];
      for(let i=0;i<promises.length;i++) {
        promises[i].then( v=> {
          count++;
          arr[i] = v;
          if (count === promises.length) {
            resolve(arr)
          }
        },r => {
          reject(r)
        })
      }
    })
  }

  // race:哪个先返回结果哪个先改变状态,并返回对应的值
  static race(promises){
    return new Promise((resolve,reject) => {
      for(let i=0;i<promises.length;i++) {
        promises[i].then( v=> {
            resolve(v)
        },r => {
          reject(r)
        })
      }
    })
  }
}

其他有趣文章的传送门:

image.png