手写Promise

173 阅读6分钟

拉勾教育大前端高薪训练营;

从事前端开发工作三年时间,作为半路出家的小白,基础比较薄弱,一直沉不下心去学习,在拉钩跟着一群大佬们一起学习,慢慢的自己也进入学习的状态,本文是自己的学习笔记,第一次写,写的不好还请大家多多提点。

Promise实例

"
```
const promise = new Promise(function (resolve, reject) {
  // 这里用于“兑现”承诺
  resolve(100) // 承诺达成
  // reject(new Error('promise rejected')) // 承诺失败
})

promise.then(function (value) {
  // 即便没有异步操作,then 方法中传入的回调仍然会被放入队列,等待下一轮执行
  console.log('resolved', value)
}, function (error) {
  console.log('rejected', error)
})

console.log('end')
```
"

实例分析

1. Promise 就是一个类 在执行这个类的时候 需要传递一个执行器进去 执行器会立即执行

2. Promise 中有三种状态 分别为 成功 fulfilled 失败 rejected 等待 pending

    pending -> fulfilled

    pending -> rejected

    一旦状态确定就不可更改

3. resolve和reject函数是用来更改状态的

    resolve: fulfilled

    reject: rejected

4. then方法内部做的事情就判断状态 如果状态是成功 调用成功的回调函数 如果状态是失败       调  用失败回调函数 then方法是被定义在原型对象中的

5. then成功回调有一个参数 表示成功之后的值 then失败回调有一个参数 表示失败后的原因

6. 同一个promise对象下面的then方法是可以被调用多次的

7. then方法是可以被链式调用的, 后面then方法的回调函数拿到值的是上一个then方法的回调函数的返回值

先新建一个MyPromise.js文件,在文件中声明一个类

```
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise  {
  constructor (executor) {
    // 捕获执行器错误
    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }

  // 状态
  status = PENDING;
  // 回调成功返回值
  value = undefined;
  // 回调失败原因
  reason = undefined;
  // 成功回调,当一个Promise被多次调用,需要将回调存放在一个数组中
  successCallback = [];
  // 失败回调,当一个Promise被多次调用,需要将回调存放在一个数组中
  failCallback = []

  resolve = value => {
    // 判断状态是否变更
    if (this.status !== PENDING) return
    // 将状态改为成功
    this.status = FULFILLED
    // 保存成功之后的值
    this.value = value
    // 处理异步情况 判断成功回调是否存在, 如果存在 则调用
    // this.successCallback && this.successCallback(this.value)
    while(this.successCallback.length) this.successCallback.shift()()
  }

  reject = reason => {
    // 判断状态是否变更,如果状态不是等待,组织变更
    if (this.status !== PENDING) return
    // 将状态改为成功
    this.status = REJECTED
    // 保存失败的原因
    this.reason = reason
    // 处理异步情况 判断失败回调是否存在, 如果存在 则调用
    // this.failCallback && this.failCallback(this.value)
    while(this.failCallback.length) this.failCallback.shift()()
  }

  then (successCallback, failCallback) {
    // then方法参数为可选
    successCallback = successCallback ? successCallback : value => value
    failCallback = failCallback ? failCallback : reason => {throw reason}
    let promise2 = new MyPromise((resolve, reject) => {
      // 判断状态
      if (this.status === FULFILLED) {
        // 获取成功回调函数的返回值,传递给下一个then,即给Promise2
        setTimeout(() => {
          try {
            let x = successCallback(this.value)
            // 判断 x 的值是普通值还是promise对象
            // 如果是普通值 直接调用resolve 
            // 如果是promise对象 查看promsie对象返回的结果 
            // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
            resolvePromise(promise2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0);
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = failCallback(this.reason)
            // 判断 x 的值是普通值还是promise对象
            // 如果是普通值 直接调用resolve 
            // 如果是promise对象 查看promsie对象返回的结果 
            // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
            resolvePromise(promise2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0);
      } else {
        // 当promise传递的是一个异步时,不会立即更改状态
        // 需要将成功回调和失败回调存储起来
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              let x = successCallback(this.value)
              // 判断 x 的值是普通值还是promise对象
              // 如果是普通值 直接调用resolve 
              // 如果是promise对象 查看promsie对象返回的结果 
              // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
              resolvePromise(promise2, x, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0);
        })
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let x = failCallback(this.reason)
              // 判断 x 的值是普通值还是promise对象
              // 如果是普通值 直接调用resolve 
              // 如果是promise对象 查看promsie对象返回的结果 
              // 再根据promise对象返回的结果 决定调用resolve 还是调用reject
              resolvePromise(promise2, x, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0);
        })
      }
    })

    return promise2
  }

  catch (failCallback) {
    return this.then(undefined, failCallback)
  }

  // 不管成功与否,finally方法始终都会调用一次
  finally (callback) {
    return this.then(value => {
      return MyPromise.resolve(callback()).then(() => value)
    }, reason => {
      return MyPromise.resolve(callback()).then(() => {throw reason})
    })
  }
  // Promise.all()方法接收的参数为一个数组,可以填入任何值,数组的顺序为得到的结果顺序保持一致
  // 调用then方法,调用结果都成功,则all方法调用结果为成功,否则即为失败
  static all (array) {
    let result = []
    let index = 0 // 当then方法中出现异步方法时,结果会出现空值的情况
    return new MyPromise((resolve, reject) => {
      function addData (key, value) {
        result[key] = value
        index++
        if (index === array.length) {
          resolve(result)
        }
      }
      for(let i = 0; i < array.length; i++) {
        let current = array[i]
        if (current instanceof MyPromise) {
          current.then(value => addData(i, value), reason => reject(reason))
        } else {
          addData(i, array[i])
        }
      }
    })
  }
  // resolver方法的作用是将给定的值转成Promise对象,返回值就是一个Promise对象,包裹这个值
  static resolve (value) {
    if (value instanceof MyPromise) return value
    return new MyPromise(resolve => resolve(value))
  }
}

function resolvePromise (promise2, x, resolve, reject) {
  // 判断函数是否发生循环调用
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (x instanceof MyPromise) {
    // Promise对象
    // x.then(value => resolve(value), reason => reject(reason))
    x.then(resolve, reject)
  } else {
    // 普通值
    resolve(x)
  }
}

module.exports = MyPromise;


```
const MyPromise = require('./MyPromise')

const promise = new MyPromise(function (resolve, reject) {
  // 异步 
  // setTimeout(() => {
  //   resolve('成功')
  //   // reject('失败')
  // }, 2000)
  // throw new Error('executor error')
  // resolve('成功')
  reject('失败')
})

// zhen方法多次调用
// promise.then(value => {
//   console.log(value)
//   throw new Error('then error')
// }, (reason) => {
//   console.log(reason.message, 1)
// }).then(value => {
//   console.log(value)
// }, (reason) => {
//   console.log(reason.message, 2)
// })

// promise.then(value => {
//   console.log(value)
// }, (reason) => {
//   console.log(reason)
// })
// promise.then(value => {
//   console.log(value)
// }, (reason) => {
//   console.log(reason)
// })

// then方法链式调用,要实现这个功能,那么then方法就要返回一个Promise对象
// 将上一个then方法的返回值传递给下一个then方法
// function other () {
//   return new MyPromise((resolve, reject) => {
//     resolve('other')
//   })
// }
// promise.then(value => {
//   console.log(value)
//   return other()
// }).then(value => {
//   console.log(value) // 100
// })

// 测试函数发生循环调用的场景
// let p1 = promise.then(value => {
//   console.log(value)
//   return p1
// })

// p1.then(value => {
//   console.log(value)
// }, reason => {
//   console.log(reason.message)
// })

// then 链式调用异常捕获
// promise.then(value => {
//   console.log(value)
//   throw new Error('then error')
//   // return 'aaa'
// }, reason => {
//   console.log(reason)
//   return 10000
// }).then(value => {
//   console.log(value)
// }, reason => {
//   console.log(reason)
// })

// 验证then方法为可选
// promise.then().then().then(value => console.log(value), reason => console.log(reason))

// 测试promise.all()
function p1 () {
  return new MyPromise(function (resolve, reject) {
    setTimeout(function () {
      resolve('p1')
    }, 2000)
  })
}
function p2 () {
  return new MyPromise(function (resolve, reject) {
    setTimeout(function () {
      resolve('p2')
    }, 2000)
  })
}
// 测试静态方法Promise.all()
MyPromise.all(['a', 'b', p1(), p2(), 'd']).then(value => {
  console.log(value)
})

// 测试静态方法Promise.resolve
MyPromise.resolve(100).then(value => console.log(value))

function p3 () {
  return new MyPromise(function (resolve, reject) {
    // resolve('p3 resolve')
    reject('p3 error')
  })
}

// 测试finally
// p3().finally(() => {
//   console.log('finally')
// }).then(value => {
//   console.log(value)
// }, reason => {
//   console.log(reason)
// })

// 测试catch方法
p3()
  .then(value => console.log(value))
  .catch(reason => console.log(reason))

注意:node版本较低时无法运行,最好升级到14.15.3