Promise从理解到还原的进阶之路

265 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

Promise

Promise的对象是一个代理对象,被代理的值在对象创建时可能是未知的,另外它允许你为异步操作的成功和失败分别绑定相应的处理方法。 常用于控制异步操作的执行顺序,而且可以让异步方法像同步方法那样返回值。它不能立即取得异步方法的返回值,但是它可以代理这个值,一旦异步操作完成,就会以及将值传递给相应的处理方法。 一个对象有以下几种状态:

  • pending: 初始状态,既不是成功,也不是失败状态。
  • fulfilled: 意味着操作成功完成。
  • rejected: 意味着操作失败。

一个对象的状态可以从pending变成fulfilledrejectedpending状态一经改变意味着此Promise对象的执行器函数已执行完毕且状态无法再次变更。当状态变更为fulfilled时传递一个成功值给Promise.then()的第一个回调函数;当已状态变更为rejected时传递一个失败信息给给Promise.then()的第二个回调函数以及Promise.catch()的第一个回调函数。因为Promise.then()Promise.catch()方法都会返回一个新的对象, 所以它们可以被链式调用。

  • Promise.resolve()

Promise并非一开始就处于待定状态,然后通过执行器函数才能转换为落定状态。通过调用Promise.resolve()静态方法,可以直接实例化一个已经为完成状态的Promise对象。

以下的两个Promise对象是一样的:

let p1 = new Promise((resolve,reject)=>resolve())
let p2 = Promise.resolve()

Promise.resolve()传入的参数可以是任何东西,包括一个错误对象 new Error()。如果传入的是一个Promise对象的话,就相当于给了一个空包装。因此Promise.resolve()可以说是一个幂等方法。

比如:

let p1 = Promise.resolve(123)
console.log(p1===Promise.resolve(Promise.resolve(p1)))//true
  • Promise.reject()

Promise.resolve()类似,首先会实例化一个处理失败的Promise对象,并抛出一个异步错误。 但是并没有照搬resolve的幂等逻辑,进行嵌套reject包装时,会抛出错误理由。

Promise的实例的静态方法

Promise 实例的方法是连接外部同步代码与内部异步代码的桥梁。这些方法可以访问异步操作所返回的数据,对异步成功或异步失败的数据进行操作,或者添加只有达到某种状态后才会执行的代码。

  • Promise.then()是为Promise实例添加结果处理程序的主要方法。这个then最多接收两个参数。onResolveonRejected处理程序。这两个参数都是可选的,如果提供的话,则会在Promise分别进入fulfilledrejected状态时执行。

  • Promise.catch()方法用于给Promise添加拒绝处理方法。这个方法只接收一个参数onRejected处理程序,相当调用Promise.then(null,onRejected)方法。

以下内容难度飙升↑

  • promise.all()使用该方法创建的Promise对象会在一组Promise对象解决之后再解决。 如果接收的数组中存在非Promise对象的话,会直接当做Promise.resolve()抛出。。这个方法接收一个可迭代的对象,返回一个新Promise:
let p1 = Promise.all([Promise.resolve(1),Promise.resolve(2),3,'4',true])
p1.then(res=>{
console.log(res);//[1,2,3,'4',true]所有Promise执行成功,返回该数组执行的结果
})

let p2 = Promise.all([Promise.reject(1),Promise.resolve(2),3,'4',true])
p2.then(res=>{
    console.log('处理成功')//数组中有一个Promise执行失败都不会执行onResoled程序
},err=>{
console.log('处理失败');//onRejected程序执行。
})
  • Promise.rece()和all类似,接收的参数为一个可迭代的对象。但是只返回第一个执行结束的Promise对象。如果第一个执行结束的状态为fulfilled则把返回值传递给onResolved程序,如果为rejected状态,则传递给onRejected程序。

简单还原一个Promise

class myPromise {
  constructor(executor) {//传入一个执行器函数executor
    this.status = 'pending'//设置初始状态为pending
    this.value = null//保存需要抛出的值
    this.onFulfilledCallbacks = []//保存成功的回调
    this.onRejectedCallbacks = []//保存失败的回调
    try {
      executor(this.resolve.bind(this), this.reject.bind(this))
    } catch (err) {//使用try catch捕获代码逻辑错误,存在则抛出
      this.reject(err)
    }
  }
  resolve(value) {
    if (this.status != 'pending') return
    this.status = 'fullfilled'
    this.value = value
    //调用then里面的回调
    while (this.onFulfilledCallbacks.length) {
      this.onFulfilledCallbacks.shift()(this.value)
    }
  }
  reject(val) {
    if (this.status != 'pending') return
    this.value = val
    this.status = 'rejected'
    while (this.onRejectedCallbacks.length) {
      this.onRejectedCallbacks.shift()(this.value)
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
    onRejected = typeof onRejected === 'function' ? onRejected : val => { throw val }
    var thenpromise = new myPromise((resolve, reject) => {
      const resolvePromose = cb => {

        setTimeout(() => {
          try {
            const x = cb(this.value)
            if (x === thenpromise) {
              throw new Error('不能返回自身。。。')
            }
            if (x instanceof myPromise) {
              x.then(resolve, reject)
            } else {
              resolve(x)
            }
          } catch (err) {
            reject(err)
            throw new Error(err)
          }
        })

      }
      if (this.status === 'fullfilled') {
        resolvePromose(onFulfilled) //判断onFulfilled返回值内容
      } else if (this.status === 'rejected') {
        resolvePromose(onRejected)
      } else if (this.status === 'pending') {//如果状态没改变则保存起来,在resolve中执行点then的回调
        this.onFulfilledCallbacks.push(resolvePromose.bind(this, onFulfilled))
        this.onRejectedCallbacks.push(resolvePromose.bind(this, onRejected))
      }
    })
    return thenpromise
  }
  static all(promise){//传入一个可迭代的对象promise
    let result = []
    let count = 0
    return new myPromise((resolve,reject)=>{//便于链式调用返回一个新的promise对象

      const addResolve = (val,index)=>{//验证数组中的执行结果是否全部执行完毕
        // result.push(val)
        result[index] = val
        count++
        if(count === promise.length){//如果长度相等则直接抛出
          return resolve(result)
        }
      }
      promise.forEach((promise,index) => {//循环这个数组
        if(promise instanceof myPromise){//如果传入的参数是一个promise对象
           promise.then(res=>{//则在该promise的.then方法中将结果和下标保存
            addResolve(res,index)
          },err=>{
           return reject(err)//如果执行出错则直接返回
          })
        }else{
          addResolve(promise,index)
        }
      });
    })
  }
  static race(promise){
    return new myPromise((resolve,reject)=>{
      promise.forEach((item,index,arr)=>{
        if(item instanceof myPromise){
          item.then(res=>{//在每个promise的.then中放入onResolved程序如果成功则直接返回
            resolve(res)
          },err=>{
            reject(err)//在每个promise的.then中放入onRejected程序如果失败则直接返回
          })
        }else{
          resolve(item)
        }
      })
    })
  }
}

写了这么多可以调试一下啦~~~嘿嘿

const p2 = new myPromise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('ok1')
    },100)
})
const p3 = new myPromise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('ok2')
    },200)
})
const p4 = new myPromise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('ok3')
    },300)
})
const pp = function(){
    console.log('pp');
}
myPromise.all([p2,p3,p4,pp]).then(res=>{
    console.log(res);
})
myPromise.race([p2,p3,p4]).then(res=>{
    console.log(res);
})

  • Promise.all()成功打印

  • Promise.rece()成功打印

1670144593324.png

----到这里就结束啦,这就是我的Promise从理解到手写的进阶之路