ES6笔记(三)Promise的使用和原理

100 阅读9分钟
Promise是一种异步请求的处理方案,是es6新增的类,为解决异步函数执行时定下一种规范
function foo() {
  return new Promise((resolve, reject) => {
    resolve()
  })
}

// new Promisr 传入的参数称之为executor
// resolve: 回调函数, 在成功时回调resolve函数
// reject: 回调函数,在失败时回调reject函数
const promise = new Promise((resolve, reject) => {
  
  resolve()
})

const fooPromise = foo()

// 在调用resolve时,promise.then(函数1,函数2) 里面的函数1就会执行,在调用reject时,函数2会执行
fooPromise.then((res) => {
  console.log(res+'函数1');
}, (error) => {
  console.log(error + '函数2');
})
// 在调用reject时,promise.catch(函数) 里面的函数就会执行
fooPromise.catch(() => {

})
Promise划分为3个状态,分为待定(pending), 已兑现(fulfiled),已拒绝(rejected),状态一旦确定下来,就不可更改
const promise = new Promise((resolve, reject) => {  // 当进入这个函数时,会给Promise划分状态, 现在到的状态是pending(待定的)
  resolve()
  reject()
})

promise.then(res => {  // 当进入这个函数时,Promise的状态是fulfiled(固定,已敲定)
   console.log('Promise的状态是fulfiled(固定,已敲定)');
}, err => {  // 当进入这个函数时,Promise的状态是rejected(已拒绝)
  console.log('Promise的状态是rejected(已拒绝)');
})
关于resolve参数,可以传入普通的值和对象也可以传入Promise,如果传入的是Promise,当前Promise的状态会由传入的Promise来决定,如果传入了一个对象,并且该对象有实现then方法,那么也会执行该then方法,由该then方法决定后续状态
const newPromise = new Promise((resolve, reject) => {
  resolve('aaaa')
})

// 传入Promise时是Promise时
const promise1 = new Promise((resolve, reject) => {  // 当进入这个函数时,当前Promise的状态会由传入的Promise来决定
  resolve(newPromise)
})

promise1.then(res => { 
   console.log('res: ' + res);  // res: aaa
}, err => { 
  console.log('err: ' + err);
})

// 传入Promise时是对象时
const promise2 = new Promise((resolve, reject) => {  // 当进入这个函数时,当前Promise的状态会由传入的对象的then方法来决定
  const obj = {
    then: function (resolve, reject) {
      resolve('resolve message')
    }
  }
  resolve(obj)
})

promise2.then(res => { 
   console.log('res: ' + res);  // res: resolve message
}, err => { 
  console.log('err: ' + err);
})
关于Promise的对象方法-then
(1)同一个Promise可以多次调用then方法
// Promise有哪些对象方法
// console.log(Object.getOwnPropertyDescriptors(Promise.prototype))

const promise = new Promise((resolve, reject) => {
  resolve('hahaha')
})

promise.then(res => {
  console.log('res1:' + res);
})

promise.then(res => {
  console.log('res2:' + res);
})
(2)then方法传入的回调函数可以有返回值,如果返回的是一个普通值,那么这个普通值会被作为一个新的Promise的resolve值。如果我们返回是一个Promise,则会根据传入的Promise的状态决定外层Promise的状态。如果返回的是一个对象,并且该对象实现了thenable
const promise = new Promise((resolve, reject) => {
  resolve('hahaha')
})


// 普通值
promise.then(res => {
  console.log(res);  // hahaha
  return 'aaa'
}).then(res => {
  console.log(res);  // aaa
  return 'bbbbb'
}).then(res => {
  console.log(res);  // bbbbb
})


// Promise
promise.then(res => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(11111)
    }, 3000);
  })
}).then(res => {
  console.log('res:' + res);  // 11111
})


// 如果返回的是一个对象,并且该对象实现了thenable
promise.then(res => {
  return {
    then: function (resolve, reject) {
      resolve(222222)
    }
  }
}).then(res => {
  console.log(res);  // 222222
})
(3) 关于Promise的catch方法
const promise = new Promise((resolve, reject) => {
  reject("rejected status")
})

// 1.当executor抛出异常时,也是会调用错误捕获的回调函数的
promise.then(undefined, (err) => {
  console.log(err);  // rejected status
})

// 2.通过catch方法来传入错误(拒绝)捕获的回调函数,阅读性更强,但是不符合Promise/a+规范
promise.catch(err => {
  console.log(err);  // rejected status
})

// 3.这里的catch会作为第一个promise异常的捕获
promise.then(res => {
  return 1111
}).catch(err => {
  console.log(err);  // rejected status
})
(3) 关于Promise的finally方法: 无论是fulfiled还是rejected状态,finally的代码都会执行
const promise = new Promise((resolve, reject) => {
  reject("rejected status")
})

promise.then(res => {
  console.log(res);  // rejected status
}).catch(err => {
  console.log(err);
}).finally(() => {
  console.log('finally code execute')  // finally code execute
})
关于Promise的类方法
1,Promise的resolve类方法与调用resolve()时相当
2,Promise的reject类方法与调用reject()时相当
3,Promise的all类方法:等多个Promise函数都执行之后回调,返回一个数组,但是有一个函数是返回reject,就只返回该rejece函数
4,Promise的allSettled类方法:,可以执行多个Promise对象,获取多个Promise状态。相比于Promise的all方法,可以获取成功或失败的所有状态
5,Promise的race类方法:返回第一个成功执行的Promise函数
6,Promise的any类方法:返回第一个成功执行的Promise函数,如果所有传入的Promise都失败,则返回异步失败,和一个 AggregateError 对象,它继承自 Error,有一个 errors 属性,属性值是由所有失败值填充的数组。(ES12)
手写Promise的实现
(1)Promise的then方法实现
// 记录状态
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'


class HMPromise {
  constructor(executor) {
    this.status = PROMISE_STATUS_PENDING
    this.value = undefined
    this.reason = undefined
    this.onFulfilledFns = []
    this.onRejectedFns = []

    const resolve = (value) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        // 为保证在then方法之后执行,使用setTimeout/queueMicrotask,queueMicrotask指把一个函数加入微任务里
        queueMicrotask(() => {
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_FULFILLED
          this.value = value
          // 执行then返回的第一个函数
          this.onFulfilledFns.forEach(fn => {
            fn(this.value)
          })
        });
      }
    }
    const reject = (reason) => {
      if(this.status === PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_REJECTED
          this.reason = reason
          // 执行then返回的第二个函数
          this.onRejectedFns.forEach(fn => {
            fn(this.reason)
          })
        });
      }
    }
    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then(onFulfilled, onRejected) {
    //链式调用
    return new HMPromise((resolve, reject) => {
      // 1.如果再then调用的时候,状态已经确定下来
      if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
        try {
          const value = onFulfilled(this.value)
          resolve(value)
        } catch (error) {
          reject(error)
        }
      }
      if(this.status === PROMISE_STATUS_REJECTED && onRejected) {
         try {
          const reason = onFulfilled(this.value)
          resolve(reason)
        } catch (error) {
          reject(error)
        }
      }
      // 2.将成功回调和失败回调放入到数组中
      if(this.status === PROMISE_STATUS_PENDING) {
        this.onFulfilledFns.push(() => {
          try {
            const value = onFulfilled(this.value)
            resolve(value)
          } catch (error) {
            reject(error)
          }
        })
        this.onRejectedFns.push(() => {
          try {
            const reason = onRejected(this.reason)
            resolve(reason)
          } catch (error) {
            reject(error)
          }
        })
      }
    })
  }

}

const promise = new HMPromise((resolve, reject) => {
  // resolve(111)
  reject(222)
})

promise.then(res => {
  console.log('res1:' + res);
  return 'aaa'
}, err => {
  console.log('err1:'+err);
  return 'bbb'
}).then((res) => {
  console.log('res2:' + res);
},err => {
  console.log('err2:' + err);
})
(2)Promise的catch和finally方法实现
// 记录状态
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'


class HMPromise {
  constructor(executor) {
    this.status = PROMISE_STATUS_PENDING
    this.value = undefined
    this.reason = undefined
    this.onFulfilledFns = []
    this.onRejectedFns = []

    const resolve = (value) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        // 为保证在then方法之后执行,使用setTimeout/queueMicrotask,queueMicrotask指把一个函数加入微任务里
        queueMicrotask(() => {
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_FULFILLED
          this.value = value
          // 执行then返回的第一个函数
          this.onFulfilledFns.forEach(fn => {
            fn(this.value)
          })
        });
      }
    }
    const reject = (reason) => {
      if(this.status === PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_REJECTED
          this.reason = reason
          // 执行then返回的第二个函数
          this.onRejectedFns.forEach(fn => {
            fn(this.reason)
          })
        });
      }
    }
    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then(onFulfilled, onRejected) {
    // 处理链式调用catch时的处理,如:在使用reject()时,promise.then(res => {}).catch(err => {})时
    onRejected = onRejected || (err => { throw err })

    onFulfilled = onFulfilled || (value => { return value })
    //链式调用
    return new HMPromise((resolve, reject) => {
      // 1.如果再then调用的时候,状态已经确定下来
      if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
        try {
          const value = onFulfilled(this.value)
          resolve(value)
        } catch (error) {
          reject(error)
        }
      }
      if(this.status === PROMISE_STATUS_REJECTED && onRejected) {
         try {
          const reason = onFulfilled(this.value)
          resolve(reason)
        } catch (error) {
          reject(error)
        }
      }
      // 2.将成功回调和失败回调放入到数组中
      if(this.status === PROMISE_STATUS_PENDING) {
        if(onFulfilled) {
          this.onFulfilledFns.push(() => {
            try {
              const value = onFulfilled(this.value)
              resolve(value)
            } catch (error) {
              reject(error)
            }
          })
        }
        if(onRejected) {
          this.onRejectedFns.push(() => {
            try {
              const reason = onRejected(this.reason)
              resolve(reason)
            } catch (error) {
              reject(error)
            }
          })
        }
      }
    })
  }

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

  finally(onFinally) {
    this.then(() => {
      onFinally()
    }, () => {
      onFinally()
    })
  }
}

const promise = new HMPromise((resolve, reject) => {
  resolve(111)
  // reject(222)
})

promise.then(res => {
  console.log('res1:' + res);
  return 'aaa'
}).catch(err => {
  console.log(err);
}).finally(() => {
  console.log(123456);
})

实现resolv和reject方法
// 记录状态
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'


class HMPromise {
  constructor(executor) {
    this.status = PROMISE_STATUS_PENDING
    this.value = undefined
    this.reason = undefined
    this.onFulfilledFns = []
    this.onRejectedFns = []

    const resolve = (value) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        // 为保证在then方法之后执行,使用setTimeout/queueMicrotask,queueMicrotask指把一个函数加入微任务里
        queueMicrotask(() => {
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_FULFILLED
          this.value = value
          // 执行then返回的第一个函数
          this.onFulfilledFns.forEach(fn => {
            fn(this.value)
          })
        });
      }
    }
    const reject = (reason) => {
      if(this.status === PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_REJECTED
          this.reason = reason
          // 执行then返回的第二个函数
          this.onRejectedFns.forEach(fn => {
            fn(this.reason)
          })
        });
      }
    }
    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then(onFulfilled, onRejected) {
    // 处理链式调用catch时的处理,如:在使用reject()时,promise.then(res => {}).catch(err => {})时
    onRejected = onRejected || (err => { throw err })

    onFulfilled = onFulfilled || (value => { return value })
    //链式调用
    return new HMPromise((resolve, reject) => {
      // 1.如果再then调用的时候,状态已经确定下来
      if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
        try {
          const value = onFulfilled(this.value)
          resolve(value)
        } catch (error) {
          reject(error)
        }
      }
      if(this.status === PROMISE_STATUS_REJECTED && onRejected) {
         try {
          const reason = onFulfilled(this.value)
          resolve(reason)
        } catch (error) {
          reject(error)
        }
      }
      // 2.将成功回调和失败回调放入到数组中
      if(this.status === PROMISE_STATUS_PENDING) {
        if(onFulfilled) {
          this.onFulfilledFns.push(() => {
            try {
              const value = onFulfilled(this.value)
              resolve(value)
            } catch (error) {
              reject(error)
            }
          })
        }
        if(onRejected) {
          this.onRejectedFns.push(() => {
            try {
              const reason = onRejected(this.reason)
              resolve(reason)
            } catch (error) {
              reject(error)
            }
          })
        }
      }
    })
  }

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

  finally(onFinally) {
    this.then(() => {
      onFinally()
    }, () => {
      onFinally()
    })
  }

  static resolve(value) {
    return new HMPromise((resolve) => {
      resolve(value)
    })
  }

  static reject(reason) {
    return new HMPromise((resolve, reject) => {
      reject(reason)
    })
  }
}

// const promise = new HMPromise((resolve, reject) => {
//   resolve(111)
//   // reject(222)
// })
HMPromise.resolve('hallo world').then(res => {
  console.log(res);
})

HMPromise.reject('Error').catch(err => {
  console.log(err);
})
实现all和allSetted方法(node环境可能不支持)
// 记录状态
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'


class HMPromise {
  constructor(executor) {
    this.status = PROMISE_STATUS_PENDING
    this.value = undefined
    this.reason = undefined
    this.onFulfilledFns = []
    this.onRejectedFns = []

    const resolve = (value) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        // 为保证在then方法之后执行,使用setTimeout/queueMicrotask,queueMicrotask指把一个函数加入微任务里
        queueMicrotask(() => {
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_FULFILLED
          this.value = value
          // 执行then返回的第一个函数
          this.onFulfilledFns.forEach(fn => {
            fn(this.value)
          })
        });
      }
    }
    const reject = (reason) => {
      if(this.status === PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_REJECTED
          this.reason = reason
          // 执行then返回的第二个函数
          this.onRejectedFns.forEach(fn => {
            fn(this.reason)
          })
        });
      }
    }
    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then(onFulfilled, onRejected) {
    // 处理链式调用catch时的处理,如:在使用reject()时,promise.then(res => {}).catch(err => {})时
    onRejected = onRejected || (err => { throw err })

    onFulfilled = onFulfilled || (value => { return value })
    //链式调用
    return new HMPromise((resolve, reject) => {
      // 1.如果再then调用的时候,状态已经确定下来
      if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
        try {
          const value = onFulfilled(this.value)
          resolve(value)
        } catch (error) {
          reject(error)
        }
      }
      if(this.status === PROMISE_STATUS_REJECTED && onRejected) {
         try {
          const reason = onFulfilled(this.value)
          resolve(reason)
        } catch (error) {
          reject(error)
        }
      }
      // 2.将成功回调和失败回调放入到数组中
      if(this.status === PROMISE_STATUS_PENDING) {
        if(onFulfilled) {
          this.onFulfilledFns.push(() => {
            try {
              const value = onFulfilled(this.value)
              resolve(value)
            } catch (error) {
              reject(error)
            }
          })
        }
        if(onRejected) {
          this.onRejectedFns.push(() => {
            try {
              const reason = onRejected(this.reason)
              resolve(reason)
            } catch (error) {
              reject(error)
            }
          })
        }
      }
    })
  }

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

  finally(onFinally) {
    this.then(() => {
      onFinally()
    }, () => {
      onFinally()
    })
  }

  static resolve(value) {
    return new HMPromise((resolve) => {
      resolve(value)
    })
  }

  static reject(reason) {
    return new HMPromise((resolve, reject) => {
      reject(reason)
    })
  }

  static all(promises) {
    return new HMPromise((resolve, reject) => {
      const values = []
      promises.forEach(promise => {
        promise.then(res => {
          values.push(res)
          if(values.length === promises.length) {
            resolve(values)
          }
        }, err => {
          reject(err)
        })
      })
    })
  }

  static allSettled(promises) {
    return new HMPromise((resolve, reject) => {
      const results = []
      promises.forEach(promise => {
        promise.then(res => {
          results.push({ status: PROMISE_STATUS_FULFILLED, value:res})
          if(results.length === promises.length) {
           resolve(results)
          }
        }, err => {
           results.push({ status: PROMISE_STATUS_REJECTED, value:err})
           if(results.length === promises.length) {
            resolve(results)
           }
        })
      })
    })
  }
}

const p1 = new HMPromise(resolve => {
  setTimeout(() => {
    resolve(111)
  }, 1000)
})

const p2 = new HMPromise((resolve, reject) => {
  setTimeout(() => {
    reject(222)
  }, 2000)
})

const p3 = new HMPromise(resolve => {
  setTimeout(() => {
    resolve(333)
  }, 3000)
})

// HMPromise.all([p1, p2, p3]).then(res => {
//   console.log(res);
// }).catch(err => {
//   console.log(err);
// })

HMPromise.allSettled([p1, p2, p3]).then(res => {
  console.log(res);
})
实现race和any方法
// 记录状态
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'


class HMPromise {
  constructor(executor) {
    this.status = PROMISE_STATUS_PENDING
    this.value = undefined
    this.reason = undefined
    this.onFulfilledFns = []
    this.onRejectedFns = []

    const resolve = (value) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        // 为保证在then方法之后执行,使用setTimeout/queueMicrotask,queueMicrotask指把一个函数加入微任务里
        queueMicrotask(() => {
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_FULFILLED
          this.value = value
          // 执行then返回的第一个函数
          this.onFulfilledFns.forEach(fn => {
            fn(this.value)
          })
        });
      }
    }
    const reject = (reason) => {
      if(this.status === PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          if(this.status !== PROMISE_STATUS_PENDING) return
          this.status = PROMISE_STATUS_REJECTED
          this.reason = reason
          // 执行then返回的第二个函数
          this.onRejectedFns.forEach(fn => {
            fn(this.reason)
          })
        });
      }
    }
    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then(onFulfilled, onRejected) {
    // 处理链式调用catch时的处理,如:在使用reject()时,promise.then(res => {}).catch(err => {})时
    onRejected = onRejected || (err => { throw err })

    onFulfilled = onFulfilled || (value => { return value })
    //链式调用
    return new HMPromise((resolve, reject) => {
      // 1.如果再then调用的时候,状态已经确定下来
      if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
        try {
          const value = onFulfilled(this.value)
          resolve(value)
        } catch (error) {
          reject(error)
        }
      }
      if(this.status === PROMISE_STATUS_REJECTED && onRejected) {
         try {
          const reason = onFulfilled(this.value)
          resolve(reason)
        } catch (error) {
          reject(error)
        }
      }
      // 2.将成功回调和失败回调放入到数组中
      if(this.status === PROMISE_STATUS_PENDING) {
        if(onFulfilled) {
          this.onFulfilledFns.push(() => {
            try {
              const value = onFulfilled(this.value)
              resolve(value)
            } catch (error) {
              reject(error)
            }
          })
        }
        if(onRejected) {
          this.onRejectedFns.push(() => {
            try {
              const reason = onRejected(this.reason)
              resolve(reason)
            } catch (error) {
              reject(error)
            }
          })
        }
      }
    })
  }

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

  finally(onFinally) {
    this.then(() => {
      onFinally()
    }, () => {
      onFinally()
    })
  }

  static resolve(value) {
    return new HMPromise((resolve) => {
      resolve(value)
    })
  }

  static reject(reason) {
    return new HMPromise((resolve, reject) => {
      reject(reason)
    })
  }

  static all(promises) {
    return new HMPromise((resolve, reject) => {
      const values = []
      promises.forEach(promise => {
        promise.then(res => {
          values.push(res)
          if(values.length === promises.length) {
            resolve(values)
          }
        }, err => {
          reject(err)
        })
      })
    })
  }

  static allSettled(promises) {
    return new HMPromise((resolve, reject) => {
      const results = []
      promises.forEach(promise => {
        promise.then(res => {
          results.push({ status: PROMISE_STATUS_FULFILLED, value:res})
          if(results.length === promises.length) {
           resolve(results)
          }
        }, err => {
           results.push({ status: PROMISE_STATUS_REJECTED, value:err})
           if(results.length === promises.length) {
            resolve(results)
           }
        })
      })
    })
  }

  static race(promises) {
    return new HMPromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(res => {
          resolve(res)
        }, err => {
          reject(err)
        })
      })
    })
  }

  static any(promises) {
    // resolve必须有一个成功的结果
    // reject所有的都失败了
    const reasons = []
    return new HMPromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(resolve, err => {
          reasons.push(err)
          if(reasons.length === promises.length) {
            reject(new AggregateError(reasons))
          }
        })

      })
    })
  }
}

const p1 = new HMPromise((resolve, reject) => {
  setTimeout(() => {
    reject(111)
  }, 1000)
})

const p2 = new HMPromise((resolve, reject) => {
  setTimeout(() => {
    reject(222)
  }, 2000)
})

const p3 = new HMPromise((resolve, reject) => {
  setTimeout(() => {
    reject(333)
  }, 3000)
})

HMPromise.any([p1, p2, p3]).then(res => {
  console.log(res);
}).catch(err => {
  console.log(err.errors);
})