Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Diy实现简单的Promise #1

Open
wuchaofan opened this issue Nov 21, 2017 · 0 comments
Open

Diy实现简单的Promise #1

wuchaofan opened this issue Nov 21, 2017 · 0 comments

Comments

@wuchaofan
Copy link
Owner

wuchaofan commented Nov 21, 2017

在js中map、filter、forEach等让我们对函数式的编程有了一些认识,在这里首先实现极简版类似的功能。

class Tool{
  constructor(value){
      this._value = value
   }
  map(fn){
    return new Tool(fn(this._value))
  }
}
new Tool(2).map((v)=> v*2).map((v) => v+10)

如果美观些可以定义一个静态函数,比如在Tool类内定义一个静态方法of,

static of(v){
  return new Tool(v)
}

Tool.of(2).map((v)=> v*2).map((v) => v+10)

异常处理就不考虑了,可以看出链式调用及返回相同类型才能实现链式操作,下面我们就来说说promise,我们通过经验来说promise有三种状态:PENDING, FULFILLED,REJECTED,分别对应等待中、成功、失败。下面我们定义这状态,

const State = {
   PENDING: 0,
   FULFILLED: 1,
   REJECTED: 2
}

然后promise初始状态肯定是PENDING了,下面我们先初步实现自定义的promise,类型就叫MyPromise吧。

class MyPromise{
   constructor(fn){
      this.state = State.PENDING
      this.value = null
      fn(this.fulfilled.bind(this), this.rejected.bind(this))
   }
   fulfilled(result){ //完成
      this.state = State.FULFILLED
      this.value = result
   }
  rejected(){ //失败
      this.state = State.REJECTED
      this.value = result
  }
  then(fulfilledCb, rejectedCb){
      if(this.state == State.FULFILLED && typeof fulfilledCb === 'function'){
          return new MyPromise((resolve, reject) => {
               resolve(fulfilledCb(this.value))
          })
      }else if(this.state == State.REJECTED && typeof rejectedCb === 'function'){
         return new MyPromise((resolve, reject) => {
               reject(rejectedCb(this.value))
          })
      }
  }
}

new MyPromise(function(resolve, reject){
    resolve(1)
}).then((res)=>{
  console.log({res})
})

先不考虑异步问题,单看实例化MyPromise等方式及功能来看已经与promise没太多不同,fulfilled和rejected分别表示处理完成后对状态的改变及保存值,then根据成功与否调用回调并且返回MyPromise实例(为了链式调用)。但是问题如果实例化如下代码会怎样呢?

new MyPromise(function(resolve, reject){
    setTimeout(function(){
        resolve(1)
    }, 4000)
}).then((res)=>{
  console.log({res})
})

对,我们如果异步操作的话then中并不能得最后的结果,此时状态要等到4秒后才会变成FULFILLED,那应该怎样解决这个问题呢,我们就要首先保存then的两个回调参数,在状态改变时再调用保存的回调。代码如下:

class MyPromise{
   constructor(fn){
      this.state = State.PENDING
      this.value = null
      this.handler = null
      fn(this.fulfilled.bind(this), this.rejected.bind(this))
   }
   fulfilled(result){ //完成
      this.state = State.FULFILLED
      this.value = result
      this.handler &&  this.handler.fulfilledCb(result)
   }
  rejected(){  //失败
      this.state = State.REJECTED
      this.value = result
      this.handler &&  this.handler.rejectedCb(result)
  }
  handleFunc(handler){
      if(this.state == State.PENDING){
          this.handler = handler
      } else if(this.state == State.FULFILLED && typeof handler.fulfilledCb === 'function'){
          handler.fulfilledCb(this.value)
          this.handler = null
      } else if(this.state == State.REJECTED && typeof handler.rejectedCb === 'function'){
          handler.rejectedCb(this.value)
          this.handler = null
      }
  }
  then(fulfilledCb, rejectedCb){
     this.handleFunc({fulfilledCb, rejectedCb})
  }
}

先不考虑then的返回值问题,看如上代码fulfilled和rejected改动及增加的handleFunc方法,用上面异步的那段实例化代码执行后可以看到已经实现的我们的目标,因为promise基本用来处理异步代码。现在我们要解决then的返回值问题也就是要返回一个MyPromise实例,改动如下:


then(fulfilledCb, rejectedCb){
     return new MyPromise((resolve, reject)=>{
         this.handleFunc({fulfilledCb: function(res){
                resolve(fulfilledCb(res))
         }, rejectedCb: function(err){
            try{
               reject(rejectedCb(err))
            }catch(exp){
               reject(exp)
            }
         }})
    })
}

如上是then的改动,要注意的是this.handleFunc中this并不是新的实例,还是then所在的对象,因为我用的是箭头函数,如果用function要先保存下this或者用bind也可,这里不再赘述。没有意外的话下面的代码就可以正确执行了。

new MyPromise(function(resolve, reject){
    setTimeout(function(){
        resolve(1)
    }, 4000)
}).then((res)=>{
  console.log({res})
  return res*20
}).then(console.log)

静态方法resolve、reject及all可以看mypromise.js 文件最后,下面是all的用例

//创建promise数组
let promiseArr = Array.from(new Array(5),(val,index)=>index+1).map((value)=>{
   return new MyPromise(function(resolve, reject){
        setTimeout(function(){
          resolve(value)
        }, value*1000)
      })
})
MyPromise.all(promiseArr).then(function(arr){
    console.log({arr});
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant