手写简化版Promise,以及Promise.all,Promise.race 怎么用

152 阅读2分钟
class Promise2 {
  #status = 'pending'
  constructor(fn){
    this.q = []
    const resolve = (data)=>{
      this.#status = 'fulfilled'
      const f1f2 = this.q.shift()
      if(!f1f2 || !f1f2[0]) return
      const x = f1f2[0].call(undefined, data)
      if(x instanceof Promise2) {
        x.then((data)=>{
          resolve(data)
        }, (reason)=>{
          reject(reason)
        })
      }else {
        resolve(x)
      }
    }
    const reject = (reason)=>{
      this.#status = 'rejected'
      const f1f2 = this.q.shift()
      if(!f1f2 || !f1f2[1]) return
      const x = f1f2[1].call(undefined, reason)
      if(x instanceof Promise2){
        x.then((data)=>{
          resolve(data)
        }, (reason)=>{
          reject(reason)
        })
      }else{
        resolve(x)
      }
    }
    fn.call(undefined, resolve, reject)
  }
  then(f1, f2){
    this.q.push([f1, f2])
  }
}

const p = new Promise2(function(resolve, reject){
  setTimeout(function(){
    reject('出错')
  },3000)
})

p.then( (data)=>{console.log(data)}, (r)=>{console.error(r)} )

Promise是异步编程的一种解决方案,比传统的回调函数要更方便,合理,避免了回调地狱。

Promise对象只有三种状态:进行中,已成功,已失败。一个Promise对象代表了一个异步操作。这个状态只能改变一次。进行中->成功,进行中->失败。

用法:new Promise创建一个promise实例,Promsie构造函数接受一个函数作为参数。这个函数的两个参数分别是resolve和reject,它们也是函数。resolve函数会在异步操作成功后被调用,把异步操作的结果作为参数传递出去;reject函数会在异步操作失败后被调用,把错误的信息作为参数传递出去。

创建了promise实例后,通过then方法给状态变化时添加回调函数。then接受两个回调函数作为参数,第一个是状态变为resolve时被调用,第二个状态变为reject被调用。

Promise.all: 接收多个promise实例作为参数,包装成一个新的promise实例const p = Promise.all([p1, p2, p3]);p的状态由p1、p2、p3决定,分成两种情况。

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

Promise.race: 同样是将多个 Promise 实例,包装成一个新的 Promise 实例.const p = Promise.race([p1, p2, p3]);只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。

Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。