js 真的是一步一步手写promise

前端异步一直是老生常谈,promise更是绕不过去的话题,那么除了会使用promise之外,能否尝试自己封装一个promise呢?网上关于这个的封装实现有很多,不过还是想一步一步的封装一下。

目录

  • 从简单使用着手
  • 添加异步处理和实例多次调用then
  • 链式调用的实现

温习promise的简单使用

先来看一下promise使用的一个小例子:

let p = new Promise(function (resolve, reject) {
  console.log('start')
  resolve('data1')
})
p.then(
  (v) => {
    console.log('success: ' + v)
  },
  (v) => {
    console.log('error: ' + v)
  }
)
console.log('end')
复制代码

运行结果如下:

针对这个例子做以下几点说明,也是需要直接记住的,因为这就好比是解答数学题的公式一样,开始一定要记牢。

  1. Promise是构造函数,new 出来的实例有then方法。
  2. new Promise时,传递一个参数,这个参数是函数,又被称为执行器函数(executor), 并执行器会被立即调用,也就是上面结果中start最先输出的原因。
  3. executor是函数,它接受两个参数 resolve reject ,同时这两个参数也是函数。
  4. new Promise后的实例具有状态, 默认状态是等待,当执行器调用resolve后, 实例状态为成功状态, 当执行器调用reject后,实例状态为失败状态。
  5. promise翻译过来是承诺的意思,实例的状态一经改变,不能再次修改,不能成功再变失败,或者反过来也不行。
  6. 每一个promise实例都有方法 then ,then中有两个参数 ,这两个参数也都是函数,当执行器调用resolve后,then中第一个参数函数会执行。当执行器调用reject后,then中第二个参数函数会执行。

那么就目前的这些功能,或者说规则,来着手写一下MyPromise构造函数吧。

1 构造函数的参数,在new 的过程中会立即执行

// 因为会立即执行这个执行器函数
function MyPromise(executor){
  executor(resolve, reject) 
}
复制代码

2 new出来的实例具有then方法

MyPromise.prototype.then = function(onFulfilled, onRejected){
    
}
复制代码

3 new出来的实例具有默认状态,执行器执行resolve或者reject,修改状态

function MyPromise(executor){
  let self = this
  self.status = 'pending' // 默认promise状态是pending
  function resolve(value){
    self.status = 'resolved' // 成功状态
  }
  function reject(reason){
    self.status = 'rejected' //失败状态
  }
  executor(resolve, reject) 
}
复制代码

4 当执行器调用resolve后,then中第一个参数函数会执行,当执行器调用reject后,then中第二个参数函数会执行

MyPromise.prototype.then = function(onFulfilled, onRejected){
  let self = this
  if(self.status === 'resolved'){
    onFulfilled()
  }
  if(self.status === 'rejected'){
    onRejected()
  }
}
复制代码

5 保证状态一旦变更不能再次改变

function Promise(executor){
  let self = this
  self.status = 'pending' // 默认promise状态是pending
  function resolve(value){
    if(self.status === 'pending'){ //保证状态一旦变更,不能再次修改
      self.value = value
      self.status = 'resolved' // 成功状态
    }
  }
  function reject(reason){
    if(self.status === 'pending'){
      self.reason = reason
      self.status = 'rejected' //失败状态
    }
  }
  executor(resolve, reject)
}
复制代码

6 执行器执行resolve方法传的值,传递给then中第一个参数函数中

function MyPromise(executor){
  let self = this
  self.value = undefined
  self.reason = undefined
  self.status = 'pending' // 默认promise状态是pending
  function resolve(value){
    if(self.status === 'pending'){ //保证状态一旦变更,不能再次修改
      self.value = value
      self.status = 'resolved' // 成功状态
    }
  }
  function reject(reason){
    if(self.status === 'pending'){
      self.reason = reason
      self.status = 'rejected' //失败状态
    }
  }
  executor(resolve, reject) // 因为会立即执行这个执行器函数
}

MyPromise.prototype.then = function(onFulfilled, onRejected){
  let self = this
  if(self.status === 'resolved'){
    onFulfilled(self.value)
  }
  if(self.status === 'rejected'){
    onRejected(self.reason)
  }
}
复制代码

尝试使用一下这个 MyPromise :

let p = new MyPromise(function (resolve, reject) {
  console.log('start')
  resolve('data2')
})
p.then(
  (v) => {
    console.log('success ' + v)
  },
  (v) => {
  console.log('error ' + v)
  }
)
console.log('end')
复制代码

运行结果如下:

结果看似对了,不过和原生的promise还是有不同的,就是success那条语句的打印顺序,不要急,MyPromise 还没有写完。

添加异步处理逻辑

还是看原生promise的使用小例子

let p = new Promise(function (resolve, reject) {
  console.log('start')
  setTimeout(function(){
      resolve('data1')
  },2000)
})
p.then(
  (v) => {
    console.log('success: ' + v)
  },
  (v) => {
    console.log('error: ' + v)
  }
)
console.log('end')
复制代码

运行结果如下

实例多次调用then方法情况(注意不是链式调用)

let p = new Promise(function (resolve, reject) {
  console.log('start')
  setTimeout(function(){
      resolve('data1')
  },2000)
})
p.then(
  (v) => {
    console.log('success: ' + v)
  },
  (v) => {
    console.log('error: ' + v)
  }
)
p.then(
  (v) => {
    console.log('success: ' + v)
  },
  (v) => {
    console.log('error: ' + v)
  }
)
console.log('end')
复制代码

运行结果如下

那么针对这种异步的情况和实例p多次调用then方法,我们上述MyPromise该如何修改呢?

猜你喜欢

转载自juejin.im/post/5c6ad98e6fb9a049d51a0f5e
今日推荐