Promise

137 阅读3分钟

定义:是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作的结果)

特点

1.对象的状态不受外界影响,只有异步操作的结果才会影响

2.一旦状态改变,就不会再变,任何时候都可以得到这个结果

3.then方法是定义在原型上的,所以可以return一个Promise再.then(链式调用)去调用它(解决回调地狱问题)

缺点

1.无法中途取消

2.处于pending状态时无法得知进度

3.内部抛出的错误,不会反应到外部,需要设置回调函数,如try...catch...?

注意点

1.如果一个Promise去resolve了另一个pending中的Promise,它的状态将由另一个Promise的异步操作结果决定

2.Promise的错误是冒泡性质,未被捕获会一直到最后的catch方法上,没有catch则不会被捕获,也不会传递到外部

静态方法

1.Promise.all(iterable) 返回一个新的Promise对象,在传入的iterable参数对象里的所有Promise对象都成功的时候才会成功(会按顺序返回结果),否则就会失败(返回失败的那一个信息)

2.Promise.race(iterable) 所有Promise中哪个返回结果最快就返回哪个的值

3.Promise.allSettled(iterable) 所有Promise都执行完毕(不管成功或失败)后返回一个新的Promise(会按顺序返回结果)

4.Promise.any(iterable)当有一个Promise返回成功时返回该Promise的值

5.Promise.resolve(val)返回一个成功的Promise

6.Promise.reject(reason)返回一个失败的Promise

扩展:手写Promise

// 学习来源 https://doc.houdunren.com/js/17%20Promise%E6%A0%B8%E5%BF%83.html#%E8%B5%B7%E6%AD%A5%E6%9E%84%E5%BB%BA
class MyPromise {
  static PENDING = 'pending'
  static FULFILLED = 'fulfilled'
  static REJECTED = 'rejected'
  // Promise.resolve
  static resolve(result) {
    return new MyPromise((resolve, reject) => {
      if (result instanceof MyPromise) {
        result.then(resolve, reject)
      } else {
        resolve(result)
      }
    })
  }
  // Promise.reject
  static reject(result) {
    return new MyPromise((_, reject) => {
      reject(result)
    })
  }
  // Promise.race
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      // 哪个最快就resolve哪个
      promises.map(promise => {
        promise.then(resolve, reject)
      })
    })
  }
  constructor(exec) {
    this.status = MyPromise.PENDING
    this.value = null
    // 当exec函数里改变状态的逻辑也是异步的话,状态还是pending,这个时候需要存起来等后面使用
    this.callbacks = []
    try {
      exec(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }
  }
  resolve(value) {
    // 调用后改变状态并保存值
    if (this.status === MyPromise.PENDING) {
      this.status = MyPromise.FULFILLED
      this.value = value
      // 有回调的话执行回调函数
      setTimeout(_ => {
        this.callbacks.map(callback => {
          callback.onFulfilled(value)
        })
      })
    }
  }
  reject(value) {
    // 调用后改变状态并保存值
    if (this.status === MyPromise.PENDING) {
      this.status = MyPromise.REJECTED
      this.value = value
      setTimeout(_ => {
        this.callbacks.map(callback => {
          callback.onRejected(value)
        })
      })
    }
  }
  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = value => value
    }
    if (typeof onRejected !== 'function') {
      onRejected = value => value
    }
    // return 实现Promise的链式调用
    let promise = new MyPromise((resolve, reject) => {
      // 当exec函数里改变状态的逻辑也是异步的情况下,状态值没有改变
      if (this.status === MyPromise.PENDING) {
        this.callbacks.push({
          onFulfilled: value => {
            this.parse(promise, onFulfilled(value), resolve, reject)
          },
          onRejected: value => {
            this.parse(promise, onRejected(value), resolve, reject)
          }
        })
      }
      if (this.status === MyPromise.FULFILLED) {
        setTimeout(() => {
          this.parse(promise, onFulfilled(this.value), resolve, reject)
        })
      }
      if (this.status === MyPromise.REJECTED) {
        setTimeout(() => {
          this.parse(promise, onRejected(this.value), resolve, reject)
        })
      }
    })
    return promise
  }
  // 复用方法,then方法里抽出复用
  parse(promise, result, resolve, reject) {
    // then方法的返回的promise不能是和then相同的Promise
    if (promise === result) {
      throw new TypeError("Chaining cycle detected for promise")
    }
    try {
      if (result instanceof MyPromise) {
        result.then(resolve, reject)
      } else {
        resolve(result)
      }
    } catch (error) {
      reject(error)
    }
  }
}

扩展:Async Await

相比Promise优点:异步转同步写法,代码更加直观

tips:

1.当某个await返回reject状态后导致整个async函数也返回reject状态,不会再往下执行,如果希望不影响的话需要在await前后套try {} catch {}

2.两个await没有前后关系的话可以使用Promise.all,不然两个不是并发执行的话会影响性能