实现自己的promise!(详细)

1.实现promise的基本结构,可以先来看一下promise的使用

const test = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 2000)
})
test.then(res => {
  console.log(res)
})

可以看出,我们在new一个promise实例的时候传入了一个执行器(resolve, reject) => { },执行函数里有两个参数,resolve、reject 方法都是在 Promise 类里定义的,外部调用这个方法时,还可以往里面传入参数,Promise 拿到这个值后保存起来,以供 .then 调用, .then() 方法需要指定成功的回调和失败的回调,根据 status 状态的不同来执行对应的回调.接下来我们就可以实现这个基本结构

class Promise {
  // 参数executor为一个执行器
  constructor(executor) {
    this.status = 'pending' //1.等待状态为pending 2.成功状态为fulfilled 3.失败状态为rejected
    this.value = ''
    this.reason = ''

    const resolve = function (value) {
      this.value = value
      if (this.status === 'pending') {
        this.status = 'fulfilled'
      }
    }
    const reject = function (reason) {
      this.reason = reason
      if (this.status === 'pending') {
        this.status = rejected
      }
    }
    executor(resolve, reject)
  }
  then (onfulfilled, onrejected) {
    if (this.status === 'fulfilled') {
      onfulfilled(this.value) // 将之前的resolve的值传入
    } else if (this.status === 'rejected') {
      onrejected(this.reason) // 将之前rejected的值传入
    }
  }
}

以上代码实现了:
1、promise状态的切换
2、then方法根据响应的状态执行对应的回调函数

2.但是以上的promise不支持异步,这里我们需要在Promise类中存放两个数组,分别保存成功回调和失败的回调,因为可以then多次,所以需要将这些函数放在数组中,代码继续补充

class Promise {
  // 参数executor为一个执行器
  constructor(executor) {
    this.status = 'pending' //1.等待状态为pending 2.成功状态为fulfilled 3.失败状态为rejected
    this.value = ''
    this.reason = ''
    this.onfulfilledCallbacks = [] // 储存成功回调的数组
    this.onrejectedCallbacks = [] // 储存失败回调的数组

    const resolve = function (value) {
      this.value = value
      if (this.status === 'pending') {
        this.status = 'fulfilled'
        if(this.onfulfilledCallbacks && this.onfulfilledCallbacks.length > 0){
          this.onfulfilledCallbacks.forEach(fn => fn(value))
        }
      }
    }
    const reject = function (reason) {
      this.reason = reason
      if (this.status === 'pending') {
        this.status = rejected
        if(this.onrejectedCallbacks && this.onrejectedCallbacks.length > 0){
          this.onrejectedCallbacks.forEach(fn => fn(reason))
        }
      }
    }
    executor(resolve, reject)
  }
  then (onfulfilled, onrejected) {
    if (this.status === 'fulfilled') {
      onfulfilled(this.value) // 将之前的resolve的值传入
    } else if (this.status === 'rejected') {
      onrejected(this.reason) // 将之前rejected的值传入
    } else if (this.status === 'pengind'){ //当异步执行status的状态还没有改变的时候,将回调函数先进行储存
      this.onfulfilledCallbacks.push(onfulfilled)
      this.onrejectedCallbacks.push(onrejected)
    }
  }
}

以上代码实现了:
1、promise状态的切换
2、then方法根据响应的状态执行对应的回调函数
3、支持promise异步

***3.***接下来要实现的就是then()方法的链式调用。
这里需要注意的是then()方法返回的是一个全新的promise实例,这样才可以保证后续的then()方法中status状态是可以改变的,继续修改代码

class Promise {
  constructor(executor) {
    this.status = 'pending'
    this.value = ''
    this.reason = ''
    this.onfulfilledCallbacks = []
    this.onrejectedCallbacks = []

    const resolve = function (value) {
      this.value = value
      if (this.status === 'pending') {
        this.status = 'fulfilled'
        if (this.onfulfilledCallbacks && this.onfulfilledCallbacks.length > 0) {
          this.onfulfilledCallbacks.forEach(fn => fn(value))
        }
      }
    }
    const reject = function (reason) {
      this.reason = reason
      if (this.status === 'pending') {
        this.status = rejected
        if (this.onrejectedCallbacks && this.onrejectedCallbacks.length > 0) {
          this.onrejectedCallbacks.forEach(fn => fn(reason))
        }
      }
    }
    executor(resolve, reject)
  }
  then (onfulfilled, onrejected) {
    const promise2 = new Promise((resolve, reject) => {
      if (this.status === 'fulfilled') {
        const x = onfulfilled(this.value) 
        resolve(x)
      } else if (this.status === 'rejected') {
        const r = onrejected(this.reason) 
        resolve(r)
      } else if (this.status === 'pengind') {
        this.onfulfilledCallbacks.push((value) => {
          const x = onfulfilled(value)
          resolve(x)
        })
        this.onrejectedCallbacks.push((reason => {
          const r = onrejected(r)
          resolve(r) // 注意失败的回调的时候状态status依然是fulfilled
        }))
      }
    })
    return promise2
  }
}

以上代码实现了:
1、promise状态的切换
2、then方法根据响应的状态执行对应的回调函数
3、支持promise异步
4、支持then()方法的链式回调,返回一个promise实例

4.接下来我们考虑的问题是,上面then()中将回调函数的返回值直接resolve出去了,如果是一个普通值是没有问题的,但是如果是一个promise对象就不可以这么做了。如果返回值是一个promise的实例,我们就必须继续调用then()方法,让这个 promise 执行,拿到这个 promise resolve 的值,继续修改代码(这里列出then方法的修改和添加的resolvePromise方法)

then (onfulfilled, onrejected) {
    const promise2 = new Promise((resolve, reject) => {
      // 这里加定时器,为了让里面的代码异步,保证传入 promise2 的时候, promise2 已经初始化完了,
      // 这也就解释了为什么 Promise 的 then 方法是异步的 
      setTimeout(() => {
        if (this.status === 'fulfilled') {
          const x = onfulfilled(this.value)
          resolvePromise(x)
        } else if (this.status === 'rejected') {
          const r = onrejected(this.reason)
          resolvePromise(r)
        } else if (this.status === 'pengind') {
          this.onfulfilledCallbacks.push((value) => {
            const x = onfulfilled(value)
            resolvePromise(x)
          })
          this.onrejectedCallbacks.push((reason => {
            const r = onrejected(r)
            resolvePromise(r) // 注意失败的回调的时候状态status依然是fulfilled
          }))
        }
      }, 0)
    })
    return promise2
  }

function resolvePromise (promise2, x, resolve, reject) {
  if (promise2 === x) {
    return new TypeError('循环引用!')
  } else if (x instanceof Promise) {
    x.then(y => {
      resolvePromise(promise2, y, resolve, reject)
    }, r => {
      reject(r)
    })
  } else {
    resolve(x)
  }
}

以上代码实现了:
1、promise状态的切换
2、then方法根据响应的状态执行对应的回调函数
3、支持promise异步
4、支持then()方法的链式回调,返回一个promise实例,并对then方法可能返回promise实例进行处理

5.接下来考虑的问题是,假如我们在new Promise的时候resolve值也是一个promise,也需要等这个promise执行完then,所以对对代码做如下修改

const resolve = function (value) {
      if(value instanceof Promise){
        return value.then(resolve, reject)
      }
      this.value = value
      if (this.status === 'pending') {
        this.status = 'fulfilled'
        if (this.onfulfilledCallbacks && this.onfulfilledCallbacks.length > 0) {
          this.onfulfilledCallbacks.forEach(fn => fn(value))
        }
      }
    }

以上代码实现了:
1、promise状态的切换
2、then方法根据响应的状态执行对应的回调函数
3、支持promise异步
4、支持then()方法的链式回调,返回一个promise实例,并对then方法可能返回promise实例进行处理
5、对第一次new Promiseresolve值可能是promise的实例做处理

6.接下来对错误捕获进行处理,其实就是加上try---catch语句

class Promise {
  constructor(executor) {
    this.status = 'pending'
    this.value = ''
    this.reason = ''
    this.onfulfilledCallbacks = []
    this.onrejectedCallbacks = []

    const resolve = function (value) {
      if (value instanceof Promise) {
        return value.then(resolve, reject)
      }
      this.value = value
      if (this.status === 'pending') {
        this.status = 'fulfilled'
        if (this.onfulfilledCallbacks && this.onfulfilledCallbacks.length > 0) {
          this.onfulfilledCallbacks.forEach(fn => fn(value))
        }
      }
    }
    const reject = function (reason) {
      this.reason = reason
      if (this.status === 'pending') {
        this.status = rejected
        if (this.onrejectedCallbacks && this.onrejectedCallbacks.length > 0) {
          this.onrejectedCallbacks.forEach(fn => fn(reason))
        }
      }
    }
    try {
      executor(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }
  then (onfulfilled, onrejected) {
    const promise2 = new Promise((resolve, reject) => {
      // 这里加定时器,为了让里面的代码异步,保证传入 promise2 的时候, promise2 已经初始化完了,
      // 这也就解释了为什么 Promise 的 then 方法是异步的 
      setTimeout(() => {
        if (this.status === 'fulfilled') {
          try {
            const x = onfulfilled(this.value)
            resolvePromise(x)
          } catch (err) {
            reject(err)
          }
        } else if (this.status === 'rejected') {
          try {
            const r = onrejected(this.reason)
            resolvePromise(r)
          } catch (err) {
            reject(err)
          }
        } else if (this.status === 'pengind') {
          this.onfulfilledCallbacks.push((value) => {
            try {
              const x = onfulfilled(value)
              resolvePromise(x)
            } catch (err) {
              reject(err)
            }
          })
          this.onrejectedCallbacks.push((reason => {
            try {
              const r = onrejected(r)
              resolvePromise(r) // 注意失败的回调的时候状态status依然是fulfilled
            } catch (err) {
              reject(err)
            }
          }))
        }
      }, 0)
    })
    return promise2
  }
}

function resolvePromise (promise2, x, resolve, reject) {
  if (promise2 === x) {
    return new TypeError('循环引用!')
  } else if (x instanceof Promise) {
    x.then(y => {
      resolvePromise(promise2, y, resolve, reject)
    }, r => {
      reject(r)
    })
  } else {
    resolve(x)
  }
}

7.promise已经基本实现了,但是我们还需要考虑一些极端情况,比如连续的then()方法返回空值,这样就需要给then()方法默认的函数,不传值的话直接返回,一行代码就可以搞定

then (onfulfilled = v => v, onrejected = r => r)

8.把静态的方法可以顺便实现一下,这里就不做过多说明

Promise.resolve = function (value) {
  return new Promise((resolve, reject) => {
    resolve(value)
  })
}
Promise.reject = function (reason) {
  return new Promise((resolve, reject) => {
    reject(reason)
  })
}

9.最后还有两个重点应该看一下,就是promise.allpromise.race的实现

Promise.all 接收一个任务数组,数组元素 (可能是 promise 或其他值) 并发执行,如果是 Promise 就执行他,拿到 resolve 的值,如果是其他普通值就直接存起来,执行完成后的值存放在一个结果数组中
Promise.all 执行后会返回一个 新的 Promise 实例,并且会将结果数组 resolve 出去,下一个 then 中可以拿到
很明显,我们只需要在内部实现一个计数器,每个任务元素完成后将计数器加 1,只要达到了任务数组的 length 长度即可

Promise.race这个方法就是:比比谁最快执行完
遍历数组参数,执行每一个元素 (同样的,注意区分 Promise 和 非Promise)
对于 Promise 实例,Promise 执行完成后,直接 resolve
对于普通值,直接 resolve

Promise.all = function (p) {
  let result = []
  let count = 0
  function processData (index, value) {
    result[index] = value
    if (++count === p.length) {
      resolve(result)
    }
  }
  p.forEach((cur, index) => {
    if (cur instanceof Promise) {
      cur.then(v => {
        processData(index, v)
      }, r => {
        this.reject(r)
      })
    } else {
      processData(cur)
    }
  })
}

Promise.race = function(p) {
  return new Promise((resolve, reject) => {
    p.forEach(cur => {
      if(cur instanceof Promise){
        cur.then(v => {
          resolve(v)
        })
      }else{
        resolve(cur)
      }
    })
  })
}

最后再来复习一下Promise的实现过程
1、promise状态的切换
2、then方法根据响应的状态执行对应的回调函数
3、支持promise异步
4、支持then()方法的链式回调,返回一个promise实例,并对then方法可能返回promise实例进行处理
5、对第一次new Promiseresolve值可能是promise的实例做处理
6、捕获并抛出错误
7、then方法设置默认值
8、promise静态方法的实现

最后的最后附上全部的代码

class Promise {
  constructor(executor) {
    this.status = 'pending' //等待状态为pending,成功为fulfilled,失败为rejected
    this.value = ''
    this.reason = ''
    this.onfulfilledCallbacks = [] //存储then中成功的回调
    this.onrejectedCallbacks = [] //存储then中失败的回调
    const resolve = (value) => {
      if (value instanceof Promise) {
        value.then(resolve, reject)
      }
      if (this.status === 'pending') {
        this.value = value
        this.status = 'fulfilled'
        if (this.onfulfilledCallbacks && this.onfulfilledCallbacks.length > 0) {
          this.onfulfilledCallbacks.forEach(fn => fn(value))
        }
      }
    }
    const reject = (reason) => {
      this.reason = reason
      if (this.status === 'pending') {
        this.status = 'rejected'
        if (this.onrejectedCallbacks && this.onrejectedCallbacks.length > 0) {
          this.onrejectedCallbacks.forEach(fn => fn(this.reason))
        }
      }
    }
    try {
      executor(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }
  then (onfulfilled = v => v, onrejected = r => r) {
    const promise2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        if (this.status === 'fulfilled') {
          try {
            const x = onfulfilled(this.value)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        } else if (this.status === 'rejected') {
          try {
            const r = onrejected(this.reason)
            resolvePromise(promise2, r, resolve, reject)
          } catch (e) {
            reject(e)
          }
        } else if (this.status === 'pending') {
          this.onfulfilledCallbacks.push(value => {
            try {
              const x = onfulfilled(value)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
          this.onrejectedCallbacks.push(reason => {
            try {
              const r = onrejected(reason)
              resolvePromise(promise2, r, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        }
      }, 0)
    })
    return promise2
  }
  catch (rejectFn) {
    return this.then(null, rejectFn) // catch方法其实就是第一个参数为null的then方法
  }
}
function resolvePromise (promise2, x, resolve, reject) {
  if (x === promise2) {
    return new TypeError('循环引用')
  } else if (x instanceof Promise) { // x是promise的实例
    x.then(y => {
      this.resolvePromise(promise2, y, resolve, reject)
    }, r => {
      reject(r)
    })
  } else { // 普通值,直接resolve
    resolve(x)
  }
}
Promise.resolve = function (value) {
  return new Promise((resolve, reject) => {
    resolve(value)
  })
}
Promise.reject = function (reason) {
  return new Promise((resolve, reject) => {
    reject(reason)
  })
}

Promise.all = function (p) {
  let result = []
  let count = 0
  function processData (index, value) {
    result[index] = value
    if (++count === p.length) {
      resolve(result)
    }
  }
  p.forEach((cur, index) => {
    if (cur instanceof Promise) {
      cur.then(v => {
        processData(index, cur)
      }, r => {
        reject(r)
      })
    } else {
      processData(index, cur)
    }
  })
}

Promise.race = function (p) {
  return new Promise((resolve, reject) => {
    p.forEach(cur => {
      if (cur instanceof Promise) {
        // 指向promise,然后再resolve
        cur.then(r => {
          resolve(r)
        })
      } else { // 不是promise的话直接resolvez
        resolve(cur)
      }
    })
  })
}

分享就到这里结束了,希望对大家有帮助!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值