方法 手写promise_手写Promise类

3c5feb67e99b38d4ea77e6434abb0c84.png

手写简单promise

1.分析promise核心逻辑

先看一段代码

let p = new Promise();
//说明Promise是一个类(class),需要new实例化
let p = new Promise((resolve, reject) => {
  resolve('success');
});
console.log(p) //Promise { 'success' }
//Promise类的构造函数接受一个参数,该参数是一个函数(执行器函数,可以参照mdn中promise说明),执行器函数在实例化后立即执行(resolve或reject)
let p = new Promise((resolve, reject) => { });
console.log(p) //Promise { <pending> }

let p1 = new Promise((resolve, reject) => {
  resolve('success');
});
console.log(p1) //Promise { 'success' }
let p2 = new Promise((resolve, reject) => {
  reject('fail');
});
console.log(p2) //Promise { <rejected> 'fail' }

let p3 = new Promise((resolve, reject) => {
  resolve('success');
  reject('fail');
});
console.log(p3) //Promise { 'success' }
//Promise有三种状态,分别是pending/fulfilled/rejected
//一旦状态确定就不可更改
//resolve和reject函数是用来更改状态的 resolve: fulfilled reject: rejected
//状态改变只能是pending=>fulfilled 或者 pending=>rejected;(参考聘,可以自己动手试试先执行reject、后执行resolve,打印看看结果)
let p = new Promise((resolve, reject) => {
  resolve('success');
  //reject('fail');
});
p.then(
  //成功回调 onfulfilled
  value => {
    console.log(value) //sucess
  }, 
  //失败回调 onrejected
  reason => {
    console.log(reason) //fail
  }
)
//then方法内部做的事情就判断状态 如果状态是成功 调用成功的回调函数 如果状态是失败 调用失败回调函数 then方法是被定义在原型对象中的
//then成功回调有一个参数 表示成功之后的值 then失败回调有一个参数 表示失败后的原因

从以上代码可以总结以下几点

  1. Promise是一个类(class),需要new实例化
  2. Promise类的构造函数接受一个参数,该参数是一个函数(执行器函数,可以参照mdn中promise说明),执行器函数在实例化后立即执行(resolve或reject)
  3. Promise有三种状态,分别是pending/fulfilled/rejected,一旦状态确定就不可更改
  4. 状态改变只能是pending=>fulfilled 或者 pending=>rejected;
  5. resolve和reject函数是用来更改状态的 resolve: fulfilled reject: rejected
  6. then方法内部做的事情就判断状态 如果状态是成功 调用成功的回调函数 如果状态是失败 调用失败回调函数 then方法是被定义在原型对象中的
  7. then成功回调有一个参数 表示成功之后的值 then失败回调有一个参数 表示失败后的原因

手动实现符合上面几点的类(myPromise)

//promise用new实例 所以是一个类 在执行这个类的时候,需要传递一个执行器函数进去,执行器函数会立即执行
const PENDING = 'pengding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  //执行器函数有两个参数resolve、reject 这两个参数也是函数,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
  //调用resolve或调用reject会更改promise状态
  //promise有三种状态,分别为pending/fulfilled/rejected
  //状态改变只能是pending=>fulfilled 或者 pending=>rejected
  status = PENDING
  //异步任务顺利执行会调用resolve函数,并传递参数value,由于该参数会传递给then方法的成功回调(successCallback),所以定义为属性值
  value = undefined
  //异步任务失败会调用reject函数,并传递参数reason,由于该参数会传递给then方法的失败回调(failCallback),所以定义为属性值
  reason = undefined
  //then函数的第一个参数,当promise执行成功时,会调用该函数,并传递resolve的参数value作为该函数的参数
  successCallback = ''
  //then函数的第二个参数,当promise执行失败时,会调用该函数,并传递reject的参数value作为该函数的参数
  failCallback = ''
  constructor(exe) {
    //执行器函数立即执行
    try {
      exe(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
  }
  resolve = (value) => {
    //判断status是否是pending状态,只有pending状态才可以继续往下执行
    if (this.status !== PENDING) return
    //异步成功执行,将status更改为FULFILLED
    this.status = FULFILLED
    //将resolve的参数放入类属性value,方便其他方法调用
    this.value = value
  }
  reject = (reason) => {
    //判断status是否是pending状态,只有pending状态才可以继续往下执行
    if (this.status !== PENDING) return
    //异步成功执行,将status更改为REJECTED
    this.status = REJECTED
    //将reject的参数放入类属性reason,方便其他方法调用
    this.reason = reason
  }
  //then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
  then = (successCallback, failCallback) => {
    //setTimeout异步执行,将promise2传入resolvePromise
    if (this.status == FULFILLED) {
      successCallback(this.value)
    } else if (this.status == REJECTED) {
      failCallback(this.reason)
    }
  }
}

2.解决异步逻辑的问题

上面的代码基本实现了之前总结的promise的特点,但是当我们异步调用执行器函数的resolve或reject方法时,会出现问题,不能打印成功回调的参数

如下报错示例2-1

const MyPromise = require('./2-Promise');
let p = new MyPromise((resolve, reject) => {
  //异步执行resolve
  setTimeout(() => {
    resolve('success');
  }, 1000);

  //reject('fail');
});
p.then(
  //成功回调 onfulfilled
  value => {
    console.log(value) //不能成功输出success
  },
  //失败回调 onrejected
  reason => {
    console.log(reason)
  }
)
//异步执行resolve时,成功回调 onfulfilled不能接收到参数

为什么会出现以上问题了?是由于当执行器函数异步执行时,then方法不能及时收到promise的状态

ac472870c05e009ba5cd640407f99a51.png

所以修改myPromise如下

//promise用new实例 所以是一个类 在执行这个类的时候,需要传递一个执行器函数进去,执行器函数会立即执行
const PENDING = 'pengding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  //执行器函数有两个参数resolve、reject 这两个参数也是函数,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
  //调用resolve或调用reject会更改promise状态
  //promise有三种状态,分别为pending/fulfilled/rejected
  //状态改变只能是pending=>fulfilled 或者 pending=>rejected
  status = PENDING
  //异步任务顺利执行会调用resolve函数,并传递参数value,由于该参数会传递给then方法的成功回调(successCallback),所以定义为属性值
  value = undefined
  //异步任务失败会调用reject函数,并传递参数reason,由于该参数会传递给then方法的失败回调(failCallback),所以定义为属性值
  reason = undefined
  //then函数的第一个参数,当promise执行成功时,会调用该函数,并传递resolve的参数value作为该函数的参数
  successCallback = ''
  //then函数的第二个参数,当promise执行失败时,会调用该函数,并传递reject的参数value作为该函数的参数
  failCallback = ''
  constructor(exe) {
    //执行器函数立即执行
    try {
      exe(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
  }
  resolve = (value) => {
    //判断status是否是pending状态,只有pending状态才可以继续往下执行
    if (this.status !== PENDING) return
    //异步成功执行,将status更改为FULFILLED
    this.status = FULFILLED
    //将resolve的参数放入类属性value,方便其他方法调用
    this.value = value
    //成功回调函数是否存在,存在则执行
    this.successCallback && this.successCallback(this.value)
  }
  reject = (reason) => {
    //判断status是否是pending状态,只有pending状态才可以继续往下执行
    if (this.status !== PENDING) return
    //异步成功执行,将status更改为REJECTED
    this.status = REJECTED
    //将reject的参数放入类属性reason,方便其他方法调用
    this.reason = reason
    //失败回调函数是否存在,存在则执行
    this.failCallback && this.failCallback(this.reason)
  }
  //then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
  then = (successCallback, failCallback) => {
    //setTimeout异步执行,将promise2传入resolvePromise
    if (this.status == FULFILLED) {
      successCallback(this.value)
    } else if (this.status == REJECTED) {
      failCallback(this.reason)
    } else {
      //解决执行器函数中的异步情况
      //将成功回调和失败回调存储起来
      this.successCallback = successCallback;
      this.failCallback = failCallback;
    }
  }
}
module.exports = MyPromise;

此时示例2-1的代码再测试可以成功打印success,说明异步问题解决

3.实现then方法的多次调用添加多个处理函数

上面的类基本实现then的单次调用,但当我们多次调用,仍然会出现问题

报错示例3-1

const MyPromise = require('./1-Promise');
let p = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('success');
  }, 10);

  //reject('fail');
});
p.then(
  //成功回调 onfulfilled
  value => {
    console.log(1, value) //不能成功输出1 success
  }
)
p.then(
  //成功回调 onfulfilled
  value => {
    console.log(2, value) //能成功输出2 success
  }
)
//问题:第一个then不能成功输出

异步多次调用then的时候会出现这种情况。出现这种情况的原因是当status处于pending状态时,我们会储存成功回调和失败回调,但是由于我们是以单变量方式储存,会导致后一个异步then调用的成功/失败回调会覆盖上一个then的成功/失败回调。

解决方案:将类的属性成功/失败回调以数组的方式调用 successCallback = [] failCallback = []

//promise用new实例 所以是一个类 在执行这个类的时候,需要传递一个执行器函数进去,执行器函数会立即执行
const PENDING = 'pengding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  //执行器函数有两个参数resolve、reject 这两个参数也是函数,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
  //调用resolve或调用reject会更改promise状态
  //promise有三种状态,分别为pending/fulfilled/rejected
  //状态改变只能是pending=>fulfilled 或者 pending=>rejected
  status = PENDING
  //异步任务顺利执行会调用resolve函数,并传递参数value,由于该参数会传递给then方法的成功回调(successCallback),所以定义为属性值
  value = undefined
  //异步任务失败会调用reject函数,并传递参数reason,由于该参数会传递给then方法的失败回调(failCallback),所以定义为属性值
  reason = undefined
  //then函数的第一个参数,当promise执行成功时,会调用该函数,并传递resolve的参数value作为该函数的参数

  successCallback = []
  //then函数的第二个参数,当promise执行失败时,会调用该函数,并传递reject的参数value作为该函数的参数

  failCallback = []
  constructor(exe) {
    //执行器函数立即执行
    try {
      exe(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
  }
  resolve = (value) => {
    //判断status是否是pending状态,只有pending状态才可以继续往下执行
    if (this.status !== PENDING) return
    //异步成功执行,将status更改为FULFILLED
    this.status = FULFILLED
    //将resolve的参数放入类属性value,方便其他方法调用
    this.value = value
    //遍历成功回调函数数组并执行
    while (this.successCallback.length) {
      this.successCallback.shift()(this.value)
    }
  }
  reject = (reason) => {
    //判断status是否是pending状态,只有pending状态才可以继续往下执行
    if (this.status !== PENDING) return
    //异步成功执行,将status更改为REJECTED
    this.status = REJECTED
    //将reject的参数放入类属性reason,方便其他方法调用
    this.reason = reason
    //遍历失败回调函数数组并执行
    while (this.failCallback.length) {
      this.failCallback.shift()(this.reason)
    }
  }
  //then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
  then = (successCallback, failCallback) => {
    if (this.status == FULFILLED) {
      successCallback(this.value)
    } else if (this.status == REJECTED) {
      failCallback(this.reason)
    } else {
      this.successCallback.push(successCallback)
      this.failCallback.push(failCallback)
    }
  }
}
module.exports = MyPromise;

示例代码3-1测试通过

4.实现then方法的链式调用

正常的Promise类可以实现链式调用,then方法的返回值应该是一个新的Promise,上面封装的类并没有实现这个特征

所以对then方法做出如下改写(仅仅改写成功回调)

//then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
  then = (successCallback, failCallback) => {
    //返回promise
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status == FULFILLED) {
        let x = successCallback(this.value)
        resolve(x)
      } else if (this.status == REJECTED) {
        failCallback(this.reason)
      } else {
        this.successCallback.push(successCallback)
        this.failCallback.push(failCallback)
      }
    });
    return promise2
  }

上面的改写会有一个问题,没有考虑successCallback(this.value)执行的异常及返回值。

当successCallback(this.value)执行异常时,需要走到reject,所以此处应当添加try{}catch(){}

当successCallback(this.value)返回值为promise时,不能直接调resolve(x)

所以做出如下分析,并封装函数处理

//判断回调结果是普通值还是promise对象

//如果是普通值直接执行resolve(x),传递x到then的成功回调

//如果是promise,判断promise返回的结果

//根据结果决定调用resolve还是调用reject

//封装函数、方便调用

then方法改写和封装处理函数dealPromise如下

then = (successCallback, failCallback) => {
    //返回promise
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status == FULFILLED) {
        try {
          let x = successCallback(this.value)
          dealPromise(x,resolve,reject)
        } catch (e) {
          reject(e)
        }
      } else if (this.status == REJECTED) {
        failCallback(this.reason)
      } else {
        this.successCallback.push(successCallback)
        this.failCallback.push(failCallback)
      }
    });
    return promise2
  }

  //类的外部封装
 function dealPromise(x, resolve, reject) {
    //判断x是否是promise对象,如果是,根据x的执行结果回调传值
    //如果x是普通值,直接调用resolve(x)
    if (x instanceof MyPromise) {
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
 }

上面的改写基本实现了then的链式调用,完全改写类如下

//promise用new实例 所以是一个类 在执行这个类的时候,需要传递一个执行器函数进去,执行器函数会立即执行
const PENDING = 'pengding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  //执行器函数有两个参数resolve、reject 这两个参数也是函数,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
  //调用resolve或调用reject会更改promise状态
  //promise有三种状态,分别为pending/fulfilled/rejected
  //状态改变只能是pending=>fulfilled 或者 pending=>rejected
  status = PENDING
  //异步任务顺利执行会调用resolve函数,并传递参数value,由于该参数会传递给then方法的成功回调(successCallback),所以定义为属性值
  value = undefined
  //异步任务失败会调用reject函数,并传递参数reason,由于该参数会传递给then方法的失败回调(failCallback),所以定义为属性值
  reason = undefined
  //then函数的第一个参数,当promise执行成功时,会调用该函数,并传递resolve的参数value作为该函数的参数

  successCallback = []
  //then函数的第二个参数,当promise执行失败时,会调用该函数,并传递reject的参数value作为该函数的参数

  failCallback = []
  constructor(exe) {
    //执行器函数立即执行
    try {
      exe(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
  }
  resolve = (value) => {
    //判断status是否是pending状态,只有pending状态才可以继续往下执行
    if (this.status !== PENDING) return
    //异步成功执行,将status更改为FULFILLED
    this.status = FULFILLED
    //将resolve的参数放入类属性value,方便其他方法调用
    this.value = value
    //遍历成功回调函数数组并执行
    while (this.successCallback.length) {
      this.successCallback.shift()()
    }
  }
  reject = (reason) => {
    //判断status是否是pending状态,只有pending状态才可以继续往下执行
    if (this.status !== PENDING) return
    //异步成功执行,将status更改为REJECTED
    this.status = REJECTED
    //将reject的参数放入类属性reason,方便其他方法调用
    this.reason = reason
    //遍历失败回调函数数组并执行
    while (this.failCallback.length) {
      this.failCallback.shift()()
    }
  }
  //then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
  then = (successCallback, failCallback) => {
    //返回promise
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status == FULFILLED) {
        try {
          let x = successCallback(this.value)
          dealPromise(x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      } else if (this.status == REJECTED) {
        try {
          let x = failCallback(this.reason)
          dealPromise(x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      } else {
        this.successCallback.push(() => {
          try {
            let x = successCallback(this.value)
            dealPromise(x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
        this.failCallback.push(() => {
          try {
            let x = failCallback(this.reason)
            dealPromise(x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
    });
    return promise2
  }
}
function dealPromise (x, resolve, reject) {
  //判断x是否是promise对象,如果是,根据x的执行结果回调传值
  //如果x是普通值,直接调用resolve(x)
  if (x instanceof MyPromise) {
    x.then(resolve, reject)
  } else {
    resolve(x)
  }
}
module.exports = MyPromise;

5.解决then的链式调用识别自身的问题,避免死循环;解决then方法的参数变成可选参数

看如下示例

let p = new Promise((resolve, reject) => {
  resolve('success');
});
let p1 = p.then(
  //成功回调 onfulfilled返回promise自身
  value => {
    return p1;
  }
)
//捕捉异常
p1.catch(
  reason => {
    console.log(reason) //抛出错误[TypeError: Chaining cycle detected for promise #<Promise>]
  }
)

Promise返回自身会抛出异常,我上面封装的Promise并没有考虑这种情况,所以再dealPromise函数中需要判断promise是否返回的是自身,如果返回自身,则抛出异常,实现后如下(其中类中做了setTimeout处理是为了方便拿到promise2)

//promise用new实例 所以是一个类 在执行这个类的时候,需要传递一个执行器函数进去,执行器函数会立即执行
const PENDING = 'pengding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  //执行器函数有两个参数resolve、reject 这两个参数也是函数,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
  //调用resolve或调用reject会更改promise状态
  //promise有三种状态,分别为pending/fulfilled/rejected
  //状态改变只能是pending=>fulfilled 或者 pending=>rejected
  status = PENDING
  //异步任务顺利执行会调用resolve函数,并传递参数value,由于该参数会传递给then方法的成功回调(successCallback),所以定义为属性值
  value = undefined
  //异步任务失败会调用reject函数,并传递参数reason,由于该参数会传递给then方法的失败回调(failCallback),所以定义为属性值
  reason = undefined
  //then函数的第一个参数,当promise执行成功时,会调用该函数,并传递resolve的参数value作为该函数的参数

  successCallback = []
  //then函数的第二个参数,当promise执行失败时,会调用该函数,并传递reject的参数value作为该函数的参数

  failCallback = []
  constructor(exe) {
    //执行器函数立即执行
    try {
      exe(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
  }
  resolve = (value) => {
    //判断status是否是pending状态,只有pending状态才可以继续往下执行
    if (this.status !== PENDING) return
    //异步成功执行,将status更改为FULFILLED
    this.status = FULFILLED
    //将resolve的参数放入类属性value,方便其他方法调用
    this.value = value
    //遍历成功回调函数数组并执行
    while (this.successCallback.length) {
      this.successCallback.shift()(this.value)
    }
  }
  reject = (reason) => {
    //判断status是否是pending状态,只有pending状态才可以继续往下执行
    if (this.status !== PENDING) return
    //异步成功执行,将status更改为REJECTED
    this.status = REJECTED
    //将reject的参数放入类属性reason,方便其他方法调用
    this.reason = reason
    //遍历失败回调函数数组并执行
    while (this.failCallback.length) {
      this.failCallback.shift()(this.reason)
    }
  }
  //then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
  then = (successCallback, failCallback) => {
     successCallback = successCallback ? successCallback : (value) => value
     failCallback = failCallback? failCallback : (reason) => { throw reason }
    //返回promise
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.status == FULFILLED) {
        setTimeout(() => {
          try {
            let x = successCallback(this.value)
            dealPromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
      } else if (this.status == REJECTED) {
        setTimeout(() => {
          try {
            let x = failCallback(this.reason)
            dealPromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
      } else {
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              let x = successCallback(this.value)
              dealPromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let x = failCallback(this.reason)
              dealPromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
      }
    });
    return promise2
  }
}
function dealPromise (promise2, x, resolve, reject) {
  //判断回调返回值x是否等于promise2,如果相等,为了避免死循环,直接返回失败回调
  if (x === promise2) {
    return reject(
      new Error('Chaining cycle detected for promise #<Promise>')
    )
  }
  //判断x是否是promise对象,如果是,根据x的执行结果回调传值
  //如果x是普通值,直接调用resolve(x)
  if (x instanceof MyPromise) {
    x.then(resolve, reject)
  } else {
    resolve(x)
  }
}
module.exports = MyPromise;

6.catch方法的实现

catch的实质是then(undefind,onrejected),实现如下

catch = (failCallback) => {
        return this.then(undefined, failCallback)
    }
    //在类中添加catch方法

7.静态方法resolve和reject的实现

resolve方法根据参数类型不同,返回结果不同

当参数是普通值,返回一个新的promise,并将参数直接resolve

当参数是promise对象,直接返回对象

//静态方法 resolve
    static resolve(data) {
        if (data instanceof MyPromise) {
            return data
        } else {
            return new MyPromise((resolve, reject) => {
                resolve(data)
            })
        }
    }

reject的实现类似

//静态方法 reject
    static reject(data) {
        if (data instanceof MyPromise) {
            return data
        } else {
            return new MyPromise((resolve, reject) => {
                reject(data.message || data)
            })
        }
    }

8.静态方法all的实现

//静态方法all,如果参数数组中的promise对象全部成功则all方法执行成功、否则失败

//原始数组中的顺序决定了结果数组中顺序,不受promise本身的异步时序影响

//静态方法all,如果参数数组中的promise对象全部成功则all方法执行成功、否则失败
    //原始数组中的顺序决定了结果数组中顺序,不受promise本身的异步时序影响
    static all = (array) => {
        //结果数组
        let result = []
        //结果数组的长度,初始长度为0
        let index = 0
        return new MyPromise((resolve, reject) => {
            let addData = (key, value) => {
                //保证结果数组的顺序与初始参数数组顺序一致
                result[key] = value
                index++
                //参数数组与结果数组长度一致才成功回调,保证成功回调不受参数数组中promise的异步影响
                //保证参数数组中的promise对象全部成功,all方法才执行成功回调、否则失败
                if (index === array.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < array.length; i++) {
                let cur = array[i]
                //当前值为promise对象
                if (cur instanceof MyPromise) {
                    cur.then(
                        (value) => addData(i, value),
                        (reason) => {
                            reject(reason)
                        }
                    )
                } else {
                    //普通值
                    addData(i, array[i])
                }
            }
        })
    }

9.静态方法race的实现

race方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。

参数一般是数组,数组中的哪个promise执行最快,就直接返回该promise的结果,由于最快的promise已经定义了status的值FULFILLED或REJECTED

剩余的promise并不能更改原promise的状态,实现如下(跑的最快的那个自动更改status)

//静态方法 race
    static race = (array) => {
        return new MyPromise((resolve, reject) => {
            for (let i = 0; i < array.length; i++) {
                let cur = array[i]
                //当前值为promise对象
                if (cur instanceof MyPromise) {
                    cur.then(
                        (value) => resolve(value),
                        (reason) => reject(reason)
                    )
                } else {
                    //普通值
                    resolve(cur)
                }
            }
        })
    }

10.finally方法的实现

finally() 方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise是否成功完成后都需要执行的代码提供了一种方式。

finally = (callback) => {
        return this.then(
            (value) => {
                return MyPromise.resolve(callback()).then(() => value)
            },
            (reason) => {
                return MyPromise.resolve(callback()).then(() => {
                    throw reason
                })
            }
        )
    }

11.最终手写的简单promise如下

//promise用new实例 所以是一个类 在执行这个类的时候,需要传递一个执行器函数进去,执行器函数会立即执行
const PENDING = 'pengding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
    //执行器函数有两个参数resolve、reject 这两个参数也是函数,当异步任务顺利完成且返回结果值时,会调用 resolve 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用reject 函数。
    //调用resolve或调用reject会更改promise状态
    //promise有三种状态,分别为pending/fulfilled/rejected
    //状态改变只能是pending=>fulfilled 或者 pending=>rejected
    status = PENDING
    //异步任务顺利执行会调用resolve函数,并传递参数value,由于该参数会传递给then方法的成功回调(successCallback),所以定义为属性值
    value = undefined
    //异步任务失败会调用reject函数,并传递参数reason,由于该参数会传递给then方法的失败回调(failCallback),所以定义为属性值
    reason = undefined
    //then函数的第一个参数,当promise执行成功时,会调用该函数,并传递resolve的参数value作为该函数的参数
    //定义成数组,方便多个回调储存
    successCallback = []
    //then函数的第二个参数,当promise执行失败时,会调用该函数,并传递reject的参数value作为该函数的参数
    //定义成数组,方便多个回调储存
    failCallback = []
    constructor(exe) {
        //执行器函数立即执行
        try {
            exe(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }
    }
    resolve = (value) => {
        //判断status是否是pending状态,只有pending状态才可以继续往下执行
        if (this.status !== PENDING) return
        //异步成功执行,将status更改为FULFILLED
        this.status = FULFILLED
        //将resolve的参数放入类属性value,方便其他方法调用
        this.value = value
        //遍历成功回调函数数组并执行
        while (this.successCallback.length) {
            this.successCallback.shift()()
        }
    }
    reject = (reason) => {
        //判断status是否是pending状态,只有pending状态才可以继续往下执行
        if (this.status !== PENDING) return
        //异步成功执行,将status更改为REJECTED
        this.status = REJECTED
        //将reject的参数放入类属性reason,方便其他方法调用
        this.reason = reason
        //遍历失败回调函数数组并执行
        while (this.failCallback.length) {
            this.failCallback.shift()()
        }
    }
    //then() 方法返回一个 Promise。它最多需要有两个参数:Promise 成功的回调函数successCallback和失败情况的回调函数failCallback。
    then = (successCallback, failCallback) => {
        successCallback = successCallback ? successCallback : (value) => value
        failCallback = failCallback? failCallback : (reason) => { throw reason }
        let promise2 = new MyPromise((resolve, reject) => {
            //setTimeout异步执行,将promise2传入dealPromise
            if (this.status == FULFILLED) {
                setTimeout(() => {
                    try {
                        let x = successCallback(this.value)
                        //resolve(x)
                        //判断回调结果是普通值还是promise对象
                        //如果是普通值直接执行resolve(x),传递x到then的成功回调
                        //如果是promise,判断promise返回的结果
                        //根据结果决定调用resolve还是调用reject
                        //封装函数、方便调用
                        dealPromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else if (this.status == REJECTED) {
                setTimeout(() => {
                    try {
                        let x = failCallback(this.reason)
                        //reject(x)
                        //判断回调结果是普通值还是promise对象
                        //如果是普通值直接执行resolve(x),传递x到then的成功回调
                        //如果是promise,判断promise返回的结果
                        //根据结果决定调用resolve还是调用reject
                        //封装函数、方便调用
                        dealPromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            } else {
                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = successCallback(this.value)
                            //resolve(x)
                            //判断回调结果是普通值还是promise对象
                            //如果是普通值直接执行resolve(x),传递x到then的成功回调
                            //如果是promise,判断promise返回的结果
                            //根据结果决定调用resolve还是调用reject
                            //封装函数、方便调用
                            dealPromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
                this.failCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = failCallback(this.reason)
                            //reject(x)
                            //判断回调结果是普通值还是promise对象
                            //如果是普通值直接执行resolve(x),传递x到then的成功回调
                            //如果是promise,判断promise返回的结果
                            //根据结果决定调用resolve还是调用reject
                            //封装函数、方便调用
                            dealPromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
            }
        })

        //返回promise
        return promise2
    }
    finally = (callback) => {
        return this.then(
            (value) => {
                return MyPromise.resolve(callback()).then(() => value)
            },
            (reason) => {
                return MyPromise.resolve(callback()).then(() => {
                    throw reason
                })
            }
        )
    }
    catch = (failCallback) => {
        return this.then(undefined, failCallback)
    }
    //静态方法all,如果参数数组中的promise对象全部成功则all方法执行成功、否则失败
    //原始数组中的顺序决定了结果数组中顺序,不受promise本身的异步时序影响
    static all = (array) => {
        //结果数组
        let result = []
        //结果数组的长度,初始长度为0
        let index = 0
        return new MyPromise((resolve, reject) => {
            let addData = (key, value) => {
                //保证结果数组的顺序与初始参数数组顺序一致
                result[key] = value
                index++
                //参数数组与结果数组长度一致才成功回调,保证成功回调不受参数数组中promise的异步影响
                //保证参数数组中的promise对象全部成功,all方法才执行成功回调、否则失败
                if (index === array.length) {
                    resolve(result)
                }
            }
            for (let i = 0; i < array.length; i++) {
                let cur = array[i]
                //当前值为promise对象
                if (cur instanceof MyPromise) {
                    cur.then(
                        (value) => addData(i, value),
                        (reason) => {
                            reject(reason)
                        }
                    )
                } else {
                    //普通值
                    addData(i, array[i])
                }
            }
        })
    }
    //静态方法 race
    static race = (array) => {
        return new MyPromise((resolve, reject) => {
            for (let i = 0; i < array.length; i++) {
                let cur = array[i]
                //当前值为promise对象
                if (cur instanceof MyPromise) {
                    cur.then(
                        (value) => resolve(value),
                        (reason) => reject(reason)
                    )
                } else {
                    //普通值
                    resolve(cur)
                }
            }
        })
    }

    //静态方法 resolve
    static resolve(data) {
        if (data instanceof MyPromise) {
            return data
        } else {
            return new MyPromise((resolve, reject) => {
                resolve(data)
            })
        }
    }

    //静态方法 reject
    static reject(data) {
        if (data instanceof MyPromise) {
            return data
        } else {
            return new MyPromise((resolve, reject) => {
                reject(data.message || data)
            })
        }
    }
}
function dealPromise(promise2, x, resolve, reject) {
    //判断回调返回值x是否等于promise2,如果相等,为了避免死循环,直接返回失败回调
    if (x === promise2) {
        return reject(
            new Error('Chaining cycle detected for promise #<Promise>')
        )
    }
    //判断x是否是promise对象,如果是,根据x的执行结果回调传值
    //如果x是普通值,直接调用resolve(x)
    if (x instanceof MyPromise) {
        x.then(resolve, reject)
    } else {
        resolve(x)
    }
}
module.exports = MyPromise

不足之处或有错误的地方还请指正,谢谢

大前端高薪训练营(拉勾教育)part1-2学习笔记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
手写Promise方法是指通过自己编写代码实现Promise的相关方法,比如Promise.all和Promise.any。在引用和引用中,作者给出了手写Promise.all和Promise.any的具体实现代码。 对于Promise.all方法手写实现,可以使用一个累加器count来判断是否所有的promise都已经成功,并将成功的结果存放在结果数组result中。当累加器count等于传入的promise数组长度时,表示所有的promise都已经成功,可以通过resolve来返回最终的成功结果。如果其中有一个promise失败,则直接通过reject返回失败结果。这里使用了Promise.resolve方法将传入的参数转化为promise对象,以便统一处理。具体的实现代码可以参考引用中的myAll方法。 对于Promise.any方法手写实现,同样可以使用一个累加器count来判断是否已经找到了成功的promise,并将成功的结果通过resolve返回。如果遍历完所有的promise都没有找到成功的,则通过reject返回失败结果。具体的实现代码可以参考引用中的myAny方法。 需要注意的是,上述的手写实现代码可能只是简单的示例,并不一定适用于所有情况,实际的实现可能还需要考虑更多的细节和边界条件。另外,手写Promise方法主要是为了更好地理解Promise的工作原理和实现方式,实际开发中通常会直接使用JavaScript中内置的Promise对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [手写promise方法(all、race、allSettled、any、finally),你会几个](https://blog.csdn.net/weixin_45774485/article/details/122462081)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值