三分钟带你手写一个完整的Promise

三分钟带你手写一个完整的Promise

实现一个基础

Promise 是类,接受一个函数参数,然后内部有status 变量和then方法,status状态初始值为pending(等待),then方法的回调函数暂存于内存中,当参数函数的需要提前执行的异步操作执行完之后,执行成功会resolve(value),status变为fulfilled,statu执行失败则会有reject(err),status变为rejected

由以上分析,可以撸出代码:

class MyPromise {
  constructor(fn) {
    this.status = 'pending'
    this.value = null
    this.err = null
    this.fulfilledCallback = null
    this.rejectedCallback = null
    const resolve = value => {
      this.status = 'fulfilled'
      this.value = value
      this.fulfilledCallback(value)
    }
    const reject = err => {
      this.status = 'rejected'
      this.err = err
      this.rejectedCallback(err)
    }
    try {
      fn(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }
  then(success, fail) {
    this.fulfilledCallback = success
    this.rejectedCallback = fail
  }
}

实现了一个基础Promise的操作,可以进行new MyPromise 传入一个异步函数,然后.then的异步操作

new MyPromise((resolve, reject) => { 
  setTimeout(() => {
    console.log(12)
    resolve(34) 
  }) 
}).then(rsp => { 
  console.log(rsp) 
})
// 输出 12 34

但是再跟一个.then 就会报错

解决链式操作的报错

但是,这样实现只有一个then函数,真正的Promis后面可以跟很多个then函数,我们可以在此基础上重新写一下then 方法,将this对象返回出来

...
then(success, fail) {
  if (this.status === 'fulfilled') {
    success(this.value)
  }
  if (this.status === 'rejected') {
    fail(this.err)
  }
  this.fulfilledCallback = success
  this.rejectedCallback = fail
  return this
}

将成功事件函数和失败事件函数升级为队列

class MyPromise {
  constructor(fn) {
    this.status = 'pending'
    this.fulfilledCallbacks = []
    this.rejectedCallbacks = []
    const resolve = value => {
      this.fulfilledCallbacks.forEach(cb=>{
        cb(value)
      })
    }
    const reject = err => {
      this.rejectedCallbacks.forEach(cb=>{
        cb(err)
      })
    }
    try {
      fn(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }
  then(success, fail) {
    if (this.status === 'fulfilled') {
      this.value = success(this.value)
    } else if (this.status === 'rejected') {
      this.err = fail(this.err)
    } else {
      this.fulfilledCallbacks.push(success)
      this.rejectedCallbacks.push(fail)
    }
    return this
  }
}

new MyPromise((resolve, reject) => {
  setTimeout(() => {
    console.log(12)
    resolve(34)
  })
}).then(rsp => {
  console.log(rsp)
}).then(rsp => {
  console.log(rsp)
})
// 12 34 34

这样下来,我们的所.then里面的回调函数都能够执行

实现下一个then里面的参数函数的实参是上一个的参数函数的返回值

Promise 除了能实现异步,还有完备的链式操作,还能够将上一个上一个then里面参数函数的返回值,作为then里面的参数函数的实参

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  })
}).then(rsp => {
  console.log(rsp)
  return 2
}).then(rsp => {
  console.log(rsp)
})
// 1 2

我们也动手实现一下,我的思路是,在resolve或者rejected之后,将这个forEach循环的函数返回值赋值给this.value,让我们试一下

...
const resolve = value => {
  this.value = value
  this.fulfilledCallbacks.forEach(cb=>{
    this.value = cb(this.value)
  })
}

new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  })
}).then(rsp => {
  console.log(rsp)
  return 2
}).then(rsp => {
  console.log(rsp)
})
// 1 2

完成

实现Promise.all

话不多说直接上代码

static all(list) {
  const results =[]
  return new MyPromise((resolve, reject) => {
    list.forEach(promise => {
      promise.then(rsp => {
        results.push(rsp)
        if (results.length === list.length) {
          resolve(results)
        }
      })
    })
  })
}

由上可知,当队列中的promise执行一个就push进入结果队列,当最后一个resolve时候(resolve的最后一个不一定是队列的最后一个);结果也就全部push进去了,(results.length === list.length)来判断,最终返回的是 resolve结果的列表。

let p1 = new MyPromise((resolve)=> resolve(1))
let p2 = new MyPromise((resolve)=> {
  setTimeout(()=>{
    resolve(2)
  }, 1000)
})
let p3 = new MyPromise((resolve)=> {
  setTimeout(()=>{
    resolve(3)
  })
})

MyPromise.all([p1, p2, p3]).then(rsp=> {
  console.log(rsp)
})

// [1,3,2]

实现Promise.resolve

Promise.resolve 的实现就相对很简单了

...
static resolve(value) {
  return new MyPromise(resolve=>{
    resolve(value)
  })
}

经过测试也是没有问题的

MyPromise.resolve(1).then(rsp => {
  console.log(rsp)
})

// 1

整套代码

整个代码如下:

class MyPromise {
  constructor(fn) {
    this.status = 'pending'
    this.fulfilledCallbacks = []
    this.rejectedCallbacks = []
    const resolve = value => {
      this.status = 'fulfilled'
      this.value = value
      this.fulfilledCallbacks.forEach(cb=>{
        this.value = cb(this.value)
      })
    }
    const reject = err => {
      this.status = 'rejected'
      this.err = err
      this.rejectedCallbacks.forEach(cb=>{
        this.value = cb(this.err)
      })
    }
    try {
      fn(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }
  then(success, fail) {
    if (this.status === 'fulfilled') {
      this.value = success(this.value)
    } else if (this.status === 'rejected') {
      this.err = fail(this.err)
    } else {
      this.fulfilledCallbacks.push(success)
      this.rejectedCallbacks.push(fail)
    }
    return this
  }
  static all(list) {
    const results =[]
    return new MyPromise((resolve, reject) => {
      list.forEach(promise => {
        promise.then(rsp => {
          results.push(rsp)
          if (results.length === list.length) {
            resolve(results)
          }
        })
      })
    })
  }
  static resolve(value) {
    return new MyPromise(resolve=>{
      resolve(value)
    })
  }
}

总结和讨论

我们也只是写了Promise相对用的多的一些功能,还有一个微任务的模拟没有实现,我们所知,resolve函数执行时候,是有个异步的,实现原理类似于node.js process.nextTick,这个涉及到底层的东西,我们这里就不做讨论

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值