实现一个Promise

实现一个Promise,来学习一下Promise的源码思想。
Promise有三种状态,分别是pending,fulfilled,rejected。默认是pending状态,当调用resolve或reject时改变状态。
状态可以从pending变成resolve或者reject,一旦改变就无法在改变回去了 。
基本用法

let p = new MyPromise((resolve,reject)=>{
  resolve('成功')
})
p.then(value=>console.log(value),err=>console.log(err))

首先需要声明一个构造函数,构造函数接受一个函数作为参数,该参数会立即执行。

function MyPromise(executor){
  executor()
}

executor接受两个参数resolve,reject

function MyPromise(executor){
  function resolve(){}
  function reject(){}
  try{
    executor(resolve,reject)
  }catch(e){
    reject(e)
 }
}

我们还需要一个变量来记录Promise的状态,调用resolve,reject时改变promise状态。
因为Promise的状态只能在pending状态改变,状态在resolve或reject状态都是不能改变的,所以需要判断。

function MyPromise(executor){
  let self =  this
  self.status = 'pending'
  function resolve(){
    if(self.status === 'pending'){
      self.status = 'resolve'
    }
  }
  function reject(){
     if(self.status === 'pending'){
      self.status = 'reject'
    }
   }
   try{
    executor(resolve,reject)
   }catch(e){
     reject(e)
   }
}

在调用resolve或reject时会传递一个值,并录下来。以便在then的回调中使用。

function MyPromise(executor){
  let self =  this
  self.status = 'pending'
  self.value
  self.reason
  function resolve(value){
    if(self.status === 'pending'){
      self.status = 'resolve'
      self.value = value
    }
  }
  function reject(reason){
     if(self.status === 'pending'){
      self.status = 'reject'
      self.reason= reason
    }
 }
 try{
    executor(resolve,reject)
 }catch(e){
   reject(e)
 }
}

Promise有一个then方法,then接受两个函数作为参数,分别是onFulfilled,onFailed。
第一个是onFulfilled,成功回调。
第二个是onFailed,失败回调。
onFulfilled,onFailed被调用时会将resolve或reject执行时保存的变量传递过去。

MyPromise.prototype.then = function(onFulfilled,onFailed){
  let self = this
  if(self.status ==='resolve')  {
    onFulfilled(self.value)
  }
  if(self.status ==='reject')  {
    onFailed(self.reason)
  }
}

但是上面的实现是不支持异步的

let p = new MyPromise((resolve,reject)=>{
  setTimeout(()=>{
    resolve('成功')  
  },2000)
})
p.then(value=>console.log(value),err=>console.log(err))

上面的代码想着会打印出来成功,但实际上是不会打印出任何东西的。
因为在执行到then的时候还没有执行resolve,这意味着Promise的状态还没有改变,没改变的话,执行then函数,是什么都不会做的。等到2秒后resolve执行了,状态改了,但是then已经执行过了一次了。
所以需要继续完善代码。

function MyPromise(executor){
  let self =  this
  self.status = 'pending'
  self.value
  self.reason
  //声明两个数组来记住then传过来的函数
  self.onResolvedCallBacks = []
  self.onRejectedCallBacks = []
  function resolve(value){
    if(self.status === 'pending'){
      self.status = 'resolve'
      self.value = value
      self.onResolvedCallBacks.forEach(function(fn){
          fn()
      })
    }
  }
  function reject(reason){
     if(self.status === 'pending'){
      self.status = 'reject'
      self.reason= reason
      self.onRejectedCallBacks.forEach(function(fn){
          fn()
      })
    }
 }
 try{
   executor(resolve,reject)
 }catch(e){
   reject(e)
 }
}

MyPromise.prototype.then = function(onFulfilled,onFailed){
  let self = this
  if(self.status ==='resolve')  {
    onFulfilled(self.value)
  }
  if(self.status ==='reject')  {
    onFailed(self.reason)
  }
  //如果执行到then,状态为pending,把传来的两个函数保存起来,等到状态改变在调用
  if(self.status ==='pending'){
    self.onResolvedCallBacks.push(function(){
      onFulfilled(self.value)
    })
    self.onRejectedCallBacks.push(function(){
      onFailed(self.reason)
    })
  }
}

再次测试,会在1秒之后打印出成功1,2秒后打印出成功2

let p1 = new MyPromise((resolve,reject)=>{
  setTimeout(()=>{
    resolve('成功1')  
  },1000)
})
let p2 = new MyPromise((resolve,reject)=>{
  setTimeout(()=>{
    resolve('成功2')  
  },2000)
})
p1.then(value=>console.log(value),err=>console.log(err))
p2.then(value=>console.log(value),err=>console.log(err))
链式调用

Promise是支持链式调用的,调用then后会返回一个新的Promise。

MyPromise.prototype.then = function(onFulfilled,onFailed){
  let self = this
  let promise2 = new MyPromise(function(resolve,reject){
    if(self.status ==='resolve')  {
      onFulfilled(self.value)
    }
    if(self.status ==='reject')  {
      onFailed(self.reason)
    }
    //如果执行到then,状态为pending,把传来的两个函数保存起来,等到状态改变在调用
    if(self.status ==='pending'){
      self.onResolvedCallBacks.push(function(){
        onFulfilled(self.value)
      })
      self.onRejectedCallBacks.push(function(){
        onFailed(self.reason)
      })
    }
  })
  return promise2
}

接下来我们需要拿到then的onFulfilled和onFailed返回的值
如果返回的是普通值,直接调用promise2的resolve,该值作为resolve的参数。这样下一个then就可以获取到该值
如果是Promise则调用这个Promise.
下面声明一个新函数resolvePromise来进行判断

function resolvePromise(promise2,x,resolve,reject){
  if((typeof x !==null && typeof x ==='object') || typeof x ==='function'){
    //如果then为function类型,则认为返回了一个Promise
    try{
      let then = x.then
      if(typeof then ==='function'){
      //返回promise处理逻辑
      }else{
        //普通对象
         resolve(x) 
      }
    }catch(e){
      reject(e)
    }
  }else{
    //普通值
    resolve(x)
  }
}

如果promise2 和 x 引用了同一个对象,需要抛出一个错误

function resolvePromise(promise2,x,resolve,reject){
  //避免返回自己
  if(promise2 === x){throw new Error('循环引用了)}

  if((typeof x !==null && typeof x ==='object') || typeof x ==='function'){
    //如果返回值then为function类型,则认为返回了一个Promise
    try{
      let then = x.then
      if(typeof then ==='function'){
      //返回promise处理逻辑
      }else{
        //普通对象
         resolve(x) 
      }
    }catch(e){
      reject(e)
    }
  }else{
    //普通值
    resolve(x)
  }
}

如果返回的是Promise的话,参照Promise/A+规范编写逻辑

    //2.3.3.1 let then = x.then.
    //2.3.3.2 如果 x.then 这步出错,那么 reject promise with e as the reason..
    //2.3.3.3 如果 then 是一个函数,then.call(x, resolvePromiseFn, rejectPromise)
    //    2.3.3.3.1 resolvePromiseFn 的 入参是 y, 执行 resolvePromise(promise2, y, resolve, reject);
    //    2.3.3.3.2 rejectPromise 的 入参是 r, reject promise with r.
    //    2.3.3.3.3 如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,后面的调用忽略。
    //    2.3.3.3.4 如果调用then抛出异常e 
    //        2.3.3.3.4.1 如果 resolvePromise 或 rejectPromise 已经被调用,那么忽略
    //       2.3.3.3.4.3 否则,reject promise with e as the reason

上面规范翻译取自https://github.com/YvetteLau/Blog/issues/2

function resolvePromise(promise2,x,resolve,reject){
  //避免返回自己
  if(promise2 === x){throw new Error('循环引用了)}
  if((typeof x !==null && typeof x ==='object') || typeof x ==='function'){
    //如果返回值then为function类型,则认为返回了一个Promise
   try{
      let then = x.then
      if(typeof then ==='function'){
      //返回promise处理逻辑
        then.call(x,function(y){
          //这里不能直接resolve(y),因为有可能会有嵌套promise的情况,需要用递归来处理
          resolvePromise(promise2,y,resolve,reject)
        },function(r){
          reject(r)  
        })
      }else{
        //普通对象
         resolve(x) 
      }
    }catch(e){
      reject(e)
    }  
  }else{
    //普通值
    resolve(x)
  }
}

根据规范我们需要确保如果resolve和reject都调用了,优先调用第一个,剩下的忽略。所以需要用一个标志来判断

function resolvePromise(promise2,x,resolve,reject){
  //避免返回自己
  if(promise2 === x){throw new Error('循环引用了')}
  if((typeof x !==null && typeof x ==='object') || typeof x ==='function'){
    let called
    //如果返回值then为function类型,则认为返回了一个Promise
    try{
      let then = x.then
      if(typeof then ==='function'){
      //返回promise处理逻辑
        then.call(x,function(y){
          //这里不能直接resolve(y),因为有可能会有嵌套promise的情况,需要用递归来处理'
          if(called){return}
          called = true
          resolvePromise(promise2,y,resolve,reject)
        },function(r){
          if(called){return}
          called = true
          reject(r)  
        })
      }else{
        //普通对象
        if(called){return}
        called = true
        resolve(x) 
      }
    }catch(e){
      if(called){return}
      called = true
      reject(e)    
    }
  }else{
    //普通值
    resolve(x)
  }
}

假如没有传递then的参数

p.then().then().then(res=>{console.log(res)})

根据规定
2.2.7.3 如果 onFulfilled 不是一个函数,promise2 以promise1的值fulfilled
2.2.7.4 如果 onRejected 不是一个函数,promise2 以promise1的reason rejected

MyPromise.prototype.then = function(onFulfilled,onFailed){
  //PromiseA+ 2.2.1 / PromiseA+ 2.2.5 / PromiseA+ 2.2.7.3 / PromiseA+ 2.2.7.4
  onFulfilled = typeof onFulfilled ==='function' ? onFulfilled : function(value)  {return value}
  onFailed = typeof onFailed==='function' ? onFailed: function(reason)  {throw reason}

  let self = this
  let promise2 = new MyPromise(function(resolve,reject){
    if(self.status ==='resolve')  {
      onFulfilled(self.value)
    }
    if(self.status ==='reject')  {
      onFailed(self.reason)
    }
    //如果执行到then,状态为pending,把传来的两个函数保存起来,等到状态改变在调用
    if(self.status ==='pending'){
      self.onResolvedCallBacks.push(function(){
        onFulfilled(self.value)
      })
      self.onRejectedCallBacks.push(function(){
        onFailed(self.reason)
      })
    }
  })
  return promise2
}

接下来我们在then中调用写好的resolvePromise方法

MyPromise.prototype.then = function(onFulfilled,onFailed){
  //PromiseA+ 2.2.1 / PromiseA+ 2.2.5 / PromiseA+ 2.2.7.3 / PromiseA+ 2.2.7.4
  onFulfilled = typeof onFulfilled ==='function' ? onFulfilled : function(value)  {return value}
  onFailed = typeof onFailed==='function' ? onFailed: function(reason)  {throw reason}

  let self = this
  var promise2 = new MyPromise(function(resolve,reject){
    if(self.status ==='resolve'){
      //规范规定onFulfilled和onFailed需要是微任务,这里使用宏任务来模拟,原生Promise的实现并不是这样的。
      setTimeout(function(){
        try{
        const x = onFulfilled(self.value)
          resolvePromise(promise2,x,resolve,reject)
        }catch(e){
          reject(e)
        }
      },0)
    }
    if(self.status ==='reject'){
      setTimeout(function(){
        try{
          const x = onFailed(self.reason)
          resolvePromise(promise2,x,resolve,reject)
        }catch(e){
          reject(e)
        }
      },0)
    }
    if(self.status ==='pending'){
      self.onResolvedCallBacks.push(function(){
        setTimeout(function(){
          try{
            const x = onFulfilled(self.value)  
            resolvePromise(promise2,x,resolve,reject)
          }catch(e){
            reject(e)
          }
        },0)
      })
      self.onRejectedCallBacks.push(function(){
        setTimeout(function(){
          try{
            const x = onFailed(self.reason)  
            resolvePromise(promise2,x,resolve,reject)
          }catch(e){
            reject(e)
          }
        },0)
      })
    }
  })
  return promise2
}

至此一个Promise已经实现了。全部代码如下

function MyPromise(executor){
  let self =  this
  self.status = 'pending'
  self.value
  self.reason
  //声明两个数组来记住then传过来的函数
  self.onResolvedCallBacks = []
  self.onRejectedCallBacks = []
  function resolve(value){
    if(self.status === 'pending'){
      self.status = 'resolve'
      self.value = value
      self.onResolvedCallBacks.forEach(function(fn){
          fn()
      })
    }
  }
  function reject(reason){
     if(self.status === 'pending'){
      self.status = 'reject'
      self.reason= reason
      self.onRejectedCallBacks.forEach(function(fn){
          fn()
      })
    }
 }
 try{
   executor(resolve,reject)
 }catch(e){
   reject(e)
 }
}

function resolvePromise(promise2,x,resolve,reject){
  //避免返回自己
  if(promise2 === x){throw new Error('循环引用了')}
  if((typeof x !==null && typeof x ==='object') || typeof x ==='function'){
    let called
    //如果返回值then为function类型,则认为返回了一个Promise
    try{
      let then = x.then
      if(typeof then ==='function'){
      //返回promise处理逻辑
        then.call(x,function(y){
          //这里不能直接resolve(y),因为有可能会有嵌套promise的情况,需要用递归来处理'
          if(called){return}
          called = true
          resolvePromise(promise2,y,resolve,reject)
        },function(r){
          if(called){return}
          called = true
          reject(r)  
        })
      }else{
        //普通对象
        if(called){return}
        called = true
        resolve(x) 
      }
    }catch(e){
      if(called){return}
      called = true
      reject(e)    
    }
  }else{
    //普通值
    resolve(x)
  }
}

MyPromise.prototype.then = function(onFulfilled,onFailed){
  //PromiseA+ 2.2.1 / PromiseA+ 2.2.5 / PromiseA+ 2.2.7.3 / PromiseA+ 2.2.7.4
  onFulfilled = typeof onFulfilled ==='function' ? onFulfilled : function(value)  {return value}
  onFailed = typeof onFailed==='function' ? onFailed: function(reason)  {throw reason}

  let self = this
  var promise2 = new MyPromise(function(resolve,reject){
    if(self.status ==='resolve'){
      //规范规定onFulfilled和onFailed需要是微任务,这里使用宏任务来模拟,原生Promise的实现并不是这样的。
      setTimeout(function(){
        try{
        const x = onFulfilled(self.value)
          resolvePromise(promise2,x,resolve,reject)
        }catch(e){
          reject(e)
        }
      },0)
    }
    if(self.status ==='reject'){
      setTimeout(function(){
        try{
          const x = onFailed(self.reason)
          resolvePromise(promise2,x,resolve,reject)
        }catch(e){
          reject(e)
        }
      },0)
    }
    if(self.status ==='pending'){
      self.onResolvedCallBacks.push(function(){
        setTimeout(function(){
          try{
            const x = onFulfilled(self.value)  
            resolvePromise(promise2,x,resolve,reject)
          }catch(e){
            reject(e)
          }
        },0)
      })
      self.onRejectedCallBacks.push(function(){
        setTimeout(function(){
          try{
            const x = onFailed(self.reason)  
            resolvePromise(promise2,x,resolve,reject)
          }catch(e){
            reject(e)
          }
        },0)
      })
    }
  })
  return promise2
}
Promise.prototype.catch

相当于调用then,但是只传递reject。

MyPromise.prototype.catch = function(onRejected){
    return this.then(function(null,onRejected))
}
Promise.resolve

Promise.resolve(value)
返回一个以给定值解析后的Promise对象。
如果value是promise则返回这个promise
如果是thenable对象,返回的promise采用这个thenable的最终状态
如果是其他情况则返回成功状态。

MyPromise.resolve = function(value){
  if(value instanceof Promise){return value}
  return new MyPromise(function(resolve,reject){
    if(value && value.then && typeof value.then === 'function'){
      value.then(resolve,reject)
    }else{
      resolve(value)
    }
  })
}
Promise.reject

Promise.reject(reason)
返回一个reject状态的promise。

MyPromise.reject = function(reason){
  return new MyPromise(function(resolve,reject){
      reject(reason)
    })
}
promise.all

一次传入多个异步任务,全部成功后返回一个数组,数组结果的顺序和传入的相同。如果有一个失败则失败。

MyPromise.all = function(promises){
  if(!Array.isArray(promises)){throw TypeError('type error of params')}
  return new MyPromise((resolve,reject)=>{
    let resultArr = []
    promises.forEach((p,index)=>{
      MyPromise.resolve(p).then(res=>{
        resultArr[index] = res
        if(resultArr.length === promises.length){
        console.log('here'+resultArr+promises.length)
          resolve(resultArr)
        }
      },err=>reject(err))
    })
  })
}
promise.race
MyPromise.race = function(promises){
    return new MyPromise((resolve,reject)=>{
        promises.forEach((p,index)=>{
            //有可能不是promise所以先用resolve解析一下
            MyPromise.resolve(p).then(resolve,reject)
        })
    })
}

你可能感兴趣的:(实现一个Promise)