手写Promise

Posted by hdj on March 20, 2020

前言

如题 手写Promise

promise规范A+

    const PENDING = 'pending'
    const RESOLVED = 'resloved'
    const REJECTED = 'rejected'
   class Promise {
    constructor(fn){
      this.state = PENDING
      this.value = undefined
      this.resolveCallback = []
      this.rejectCallback = []
      
      const resolve = (value)=>{
          if(value instanceof Promise){
              return value.then((v)=>{resolve(v)})
          }
          if(this.state === PENDING){
              this.state = RESOLVED
              this.value = value
              this.resolveCallback.forEach(cb => cb())
          }

      }
        
      const reject =(val)=>{
        if(this.state === PENDING){
            this.state = REJECTED
            this.value = value
            this.rejectCallback.forEach(cb => cb())
        }
      }
      try{
          fn(resolve,reject)
      }
      catch(e){
        reject(e)
      }

    }
    then(onFullFilled,onRejected){
        onFullFilled = typeOf onFullFilled === 'function'? onFullFilled: v=> v;
        onRejected = typeOf onRejected === 'function'? onRejected: err=> { throw err};
             
        let promise2 = new Promise((resolve,reject)=>{
           if(this.state === PENDING){
              this.resolveCallback.push(()=>{
                setTimeout(()=>{
                  try{
                   const x = onFullFilled(this.value)
                   resolvePromise(promise2,x,resolve,reject)
                  }catch(err){
                    reject(err)
                  }

                },0)
              })
              this.rejectCallback.push(()=>{
                setTimeout(()=>{
                  try{
                   const x = onRejected(this.value)
                   resolvePromise(promise2,x,resolve,reject)
                  }catch(err){
                    reject(err)

                  }
                },0)
              })
           }
          
           if(this.state === RESOLVED){
            setTimeout(()=>{
                try{
                 const x = onFullFilled(this.value)
                 resolvePromise(promise2,x,resolve,reject)
                }catch(err){
                  reject(err)
                }
              },0)

           }

           if(this.state === REJECTED){
            setTimeout(()=>{
                try{
                 const x = onRejected(this.value)
                 resolvePromise(promise2,x,resolve,reject)
                }catch(err){
                  reject(err)
                }
              },0)

           }

        })
      
     return promise2     
    }
    catch(val){
      return Promise.reject(val)
    }

} 
Promise.resolve = function(val){
    return new Promise((reslove,reject)=>{
        resolve(val)
    })
}
Promise.reject = function(val){
    return new Promise((reslove,reject)=>{
        reject(val)
    })
}

Promise.all = function(promises){
  let pArr = []
  let i = 0
  function dealRespromiseData(i,data,resolve){
      pArr[i] = data
      i++
      if(i === promises.length){
        resolve(pArr)
      }
  }
  return new Promise((resolve,reject)=>{
    promises.forEach((p,index)=>{
        p.then(val =>{
          dealRespromiseData(index,val,resolve)
        })
    })
  })
}
Promise.race = function(promises){
return new Promise((resolve,reject)=>{
    promises.forEach(p=>{
        p.then(val=>{
            reslove(val)
        })
    })
})
}


function resolvePromise(promise2,x,resolve,reject){
    if(promise2 === x){
        return reject(new Error('can not be same value'))
    }
    let called = false
    if(x!==null && (typeOf x === 'object' ||typeOf x === 'function') ){
       const then = x.then
       if( then === 'function'){
         try{
             then.call((
                 x,
                 (y)=>{
                     if(called) return
                    called = true
                    resolvePromise(promise2,y,resolve,reject)
                 },
                 (err)=>{
                     if(called) return
                     called = true
                     reject(err)
                 },
             ))
         }
         catch(e){
            if(called) return
            called = true
            reject(err)
         }

       }else{
        resolve(x)  
       }
            
    }else{
        resolve(x)
    }
}

验证我们的promise是否正确

  1. 先在后面加上下述代码
  2. npm 有一个promises-aplus-tests插件 npm i promises-aplus-tests -g 可以全局安装 mac用户最前面加上sudo
  3. 命令行 promises-aplus-tests [js文件名] 即可验证

     Promise.defer = Promise.deferred = function () {
             // npm install promises-aplus-tests 用来测试自己的promise 符不符合promisesA+规范
             // 目前是通过他测试 他会测试一个对象
             // 语法糖
             let dfd = {}
             dfd.promise = new Promise((resolve,reject)=>{
               dfd.resolve = resolve;
               dfd.reject = reject;
             });
             return dfd;
           }
     module.exports = Promise;