Promise解决了什么问题

  • Promise解决了回调天堂的问题,一层一层嵌套的代码十分不美观,它带来了两个问题,可读性问题和信赖问题
  • 信赖问题,在传统的异步编程中,往往会呈现回调过早、回调过晚或者没有回调、回调次数过多等等一些问题
  • Promise最大的益处是在异步执行的流程中,把执行代码和处理结果的代码清晰地拆散了,Promise 将回调嵌套改成了链式调用,减少了可读性和信赖问题

看一个最简略的Promise的应用

const p1 = new Promise((resolve, reject) => {    resolve('success')})p1.then((res) => console.log('res'), err => console.log(err))// success

Promise外围

  • promise就是一个类,在执行这个类的时候,须要传递一个执行器 executor(),执行器会立刻执行
  • executor 承受两个参数,别离是 resolve 和 reject
  • promise中有三种状态,别离为 胜利 fulfilled,失败 rejected, 期待 pending,
  • promise 只能从 pendingrejected, 或者从 pendingfulfilled,
  • promise 的状态一旦确认,就不会再扭转
  • then办法外部做的事件就是判断状态,如果状态是胜利,调用胜利的回调函数,如果状态是失败,调用失败的函数,then办法是被定义在原型对象上的
  • promise 能够then屡次,promise 的then 办法返回一个 promise
  • then 的参数 onFulfilledonRejected 是可选的
  • then胜利回调有一个参数,示意胜利之后的值,then失败回调有一个参数,示意失败后的起因

咱们能够写出Promise的大抵构造

const PENDING = 'pending'; // 期待const FULFILLED = 'fulfilled'; // 胜利const REJECTED = 'rejected'; // 失败class MyPromise {  constructor (executor) {    executor(this.resolve, this.reject)  }  // promise 状态  status = PENDING;  // 胜利后的值  value = undefined;  // 失败后的值  reason = undefined;  resolve = () => {    // 如果状态不是期待,阻止程序向下运行    if (this.status !== PENDING) return;    // 将状态更改为胜利    this.status = FULFILLED;    // 保留胜利之后的值    this.value = value;  }  reject = () => {    // 如果状态不是期待,阻止程序向下运行    if (this.status !== PENDING) return;    // 将状态更改为失败    this.status = REJECTED;    // 保留失败后的起因    this.reason = reason;  }  then (successCallback, failCallback) {    // 判断状态    if (this.status === FULFILLED) {      successCallback();    } else if (this.status === REJECTED) {      failCallback()    }  }}

测试一下

let p1 = new MyPromise((resolve, reject) => {  resolve('胜利')})p1.then((value) => {  console.log(value)}, reason => {  console.log(reason)})// 胜利

Promise A+标准

Promise A+标准中文

Promise A+标准英文

依据标准咱们能够总结几条外围的规定,更多的标准咱们能够查看文档进行总结~

  • 一个 Promise 的以后状态必须为以下三种状态中的一种:期待态(Pending)执行态(Fulfilled)和回绝态(Rejected)
  • Promise 的 then 办法承受两个参数 promise.then(onFulfiled, onRejected)
  • then 办法能够被同一个 Promise 调用屡次
  • then 办法必须返回一个 Promise 对象

上面咱们将一步步来实现Promise

Promise中退出异步逻辑

// 胜利回调successCallback = undefined;// 失败后的回调faliCallback = undefined;resolve = value => {  // 判断胜利回调是否存在,如果存在 调用  this.successCallback && this.successCallback(this.value)}reject = reason => {  // 判断失败回调是否存在,如果存在则调用  this.faliCallback && this.faliCallback(this.reason)}then (successCallback, faliCallback) {  // 判断状态  if (this.status === FULFILLED) {    successCallback(this.value)  } else if (this.status === REJECTED) {    faliCallback(this.reason);  } else {    // 期待    // 将期待回调和失败回调存储起来    this.successCallback = successCallback;    this.faliCallback = faliCallback;  }}

测试一下

let promise = new MyPromise((resolve, reject) => {  setTimeout(() => {    resolve('success')  }, 2000)})promise.then(value => {  console.log(value)}, reason => {  console.log(reason)})// success

实现then 办法屡次调用增加多个处理函数

  • 分同步和异步状况解决
  • 如果是同步间接调用回调函数,如果是异步,须要将回调函数存储起来
  • 首先把胜利回调和失败回调的值变成数组
  • 接着将胜利回调和失败回调应用push办法把胜利回调push进数组
  • 当promise的状态变成胜利或者失败时,咱们须要顺次调用数组中的回调函数
  • 当胜利回调的数组长度不等于0,就有回调函数,while 循环从前往后执行调用shift()办法,每执行一个删除一个,直到数组长度为0
successCallback = [];failCallback = [];// 将原来代码批改为// this.successCallback && this.successCallback(this.value);while (this.successCallback.length) this.successCallback.shift()(this.value);// this.faliCallback && this.faliCallback(this.reason);while (this.faliCallback.length) this.faliCallback.shift()(this.reason);

测试一下

let promise = new MyPromise((resolve, reject) => {  // resolve('大白菜~~')  // reject('失败')  setTimeout(() => {    resolve('大白菜~')  }, 2000)})promise.then(value => {  console.log(value)}, reason => {  console.log(reason)})// 大白菜

实现then办法链式调用

  • Promisethen办法是能够链式调用的,前面的then办法回调函数拿到的值实际上是拿到上一个then办法回调函数的返回值
  • 实现then办法的链式调用, then办法是Promise对象上面的,如果要实现链式调用,那么每一个then办法都应该返回一个Promise对象

留神

  • 在链式调用then办法的时候,回调函数能够返回一个一般值,和一个promise对象
  • 如果返回的是一般值,咱们能够间接调用resolve(x)把这个一般值传递给下一个promise对象
  • 如果是promise对象的话,咱们须要查看返回的promise对象状态,如果状态是胜利的,咱们须要调用resolve办法,把胜利的状态传递给它,

如果是失败的,须要把reject传递给下一个promise对象

// 革新then办法then (successCallback, faliCallback) {  let promise2 = new myPromise((resolve, reject) => {    // 判断状态    if (this.status === FULFILLED) {      let x = successCallback(this.value);      // 判断x的是是一般值还是promise对象      // 如果是一般值, 间接调用resolve      // 如是是promise对象 查看promise对象返回的后果      // 在依据promise对象返回的后果 决定调用resovle还是reject      resolvePromise(x, resolve, reject)      // resolve(x)    } else if (this.status === REJECTED) {      faliCallback(this.reason);    } else {      // 期待      // 将期待回调和失败回调存储起来      this.successCallback.push(successCallback);      this.faliCallback.push(faliCallback);    }  });  return promise2;}// 定义resolvePromise办法function resolvePromise(x, resolve, reject) {  if (x instanceof myPromise) {    // promise对象    x.then(resolve, reject);  } else {    // 一般值  }}// 测试一下let promise = new MyPromise((resolve, reject) => {  resolve('大白菜~~')  // reject('失败')  // setTimeout(() => {  //   resolve('大白菜~')  // }, 2000)})function other () {  return new MyPromise((resolve, reject) => {    resolve('other');  })}promise.then(value => {  console.log(value);  return other();}).then(value => {  console.log(value)})// 大白菜// other

Promise then办法链式调用辨认Promise对象主动返回

当链式调用Promise 对象上面的then办法的时候, 在then办法回调函数中能够返回Promise 对象,但咱们须要思考另外一种状况,在then办法回调函数中不能返回以后这个then办法他所返回的Promise对象, 如果返回了then办法返回的Promise对象,就会产生循环调用。

示例

let promise = new Promise((resolve, reject) => {  resolve('大白菜')})let p1 = promise.then((value) => {  console.log(value)  return p1})// 报错// TypeError: Chaining cycle detected for promise #<Promise>

解决

  • then办法中返回的 Promise 对象就是promise 2
  • 那么胜利的回调 返回的Promise对象就是 x
  • 判断 peomise2x 是否相等,
  • 相等就是本人返回了本人, 须要将状态放到reject

革新代码

// 将then办法外面革新成异步代码退出setTimeout()setTimeout(() => {  // 执行胜利调用胜利回调函数,拿到返回值  let x = successCallback(this.value);  resolvePromise(promise2, x, resolve, reject)}, 0)// 革新resolvePromise办法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(resolve, reject)  } else {    // 一般值    resolve(x)  }}

测试一下

let promise = new MyPromise((resolve, reject) => {  resolve('大白菜')})let p1 = promise.then((value) => {  console.log(value)  return p1})p1.then((value) => {    console.log(value)}, (err) => {    console.log(err)})// 大白菜// Chaining cycle detected for promise #<Promise>

捕捉谬误及then链式调用其余状态

在执行结构器中退出try catch

constructor (executor) {  try {    executor(this.resolve, this.reject)  } catch (e) {    this.reject(e);  }}// 测试一下let promise = new myPromise((resolve, reject) => {  throw new Error('executor error')})promise.then(value => {  console.log(value)}, reason => {  console.log(reason.message)})// 胜利捕捉谬误 excutor error

then 回调函数捕捉谬误

// 在then办法的setTimeout 中增加try catchsetTimeout(() => {  try {    let x = successCallback(this.value);    resolvePromise(promise2, x, resolve, reject)  } catch (e) {    reject(e)  }}, 0)// 测试let promise = new MyPromise((resolve, reject) => {  resolve('大白菜')})promise.then((value) => {  console.log(value)  throw new Error('then error')}, (err) => {  console.log(err.message)}).then((value) => {  console.log(value)}, reason => {  console.log('~~~')  console.log(reason.message)})// 大白菜// ~~~// then error

批改失败的中央

setTimeout(() => {  try {    let x = failCallback(this.reason);    resolvePromise(promise2, x, resolve, reject)  } catch (e) {    reject(e)  }}, 0)// 测试一下let promise = new MyPromise((resolve, reject) => {  reject('失败')})promise.then(value => {  console.log(value)}, reason => {  console.log(reason)  return '大白菜~~';}).then(value => {  console.log(value)})// 失败// 大白菜~~

当是异步的时候

将原来的代码改成

this.successCallback.push(successCallback);this.failCallback.push(failCallback);this.successCallback.push(() => {  setTimeout(() => {    try {      let x = successCallback(this.value);      resolvePromise(promise2, x, resolve, reject)    } catch (e) {      reject(e)    }  }, 0)})this.failCallback.push(() => {  setTimeout(() => {    try {      let x = failCallback(this.reason);      resolvePromise(promise2, x, resolve, reject)    } catch (e) {      reject(e)    }  }, 0)})// 而后resolve和reject就不须要传值了while (this.successCallback.length) this.successCallback.shift()();while (this.failCallback.length) this.failCallback.shift()();

测试一下

let promise = new MyPromise((resolve, reject) => {  setTimeout(() => {    resolve('success~~~~');    // reject('error~~~~')  }, 2000)})promise.then((value) => {  console.log(value)  return '米糕';}, reason => {  console.log(reason)  return '大白菜';}).then((value) => {  console.log(value);})// suceess~~~// 米糕

到这里Promise的外围性能就根本曾经实现啦~~~

将then办法的参数变成可选参数

  • then办法有两个可选参数,一个胜利回调,一个失败回调
  • 这两个参数都是可选参数,退出遇到一下状况
let promise = new Promise((resolve, reject) => {  resolve(100)})promise  .then()  .then()  .then(value => {    cosole.log(value)  })
  • 在这种状况下, promise 会顺次往下传递
  • 咱们须要在then办法中判断是否有参数,如果不存在就补一个参数,这样状态就能够顺次向后传递了

批改Promise的代码
在then办法咱们判断successCallback和failCallback是否存在

successCallback = successCallback ? successCallback : value => value;failCallback = failCallback ? failCallback : reason => { throw reason };

测试一下

let promise = new MyPromise((resolve, reject) => {  setTimeout(() => {    resolve('success');    // reject('reject');  }, 2000)})promise.then().then().then(value => {  console.log(value);}, reason => {  console.log(reason);})// success// reject

Promise.all实现

  • 接管一个数组作为参数填充,在数组中能够填入任意值,包含一般值和Promise对象,数组的程序肯定是失去后果的程序
  • Promise.all 特点在all 中的所有Promise 对象, 如果他的状态都是胜利的,那么 all办法就是胜利的,如果有一个是失败的, 那么就是失败的
  • 利用类 .上all 所以 all 是一个静态方法
  • Promise.all 是解决异步并发问题, 容许依照异步代码调用的程序失去异步代码执行的后果, 因为all 办法是静态方法, all 后面定义 static 关键字, all 办法接管一个数组作为参数, all办法的返回值也是一个Promise 对象, 在Promise 对象中通过循环 传递的数组,在循环的过程判断是一般值,还是Promise 对象, 进行不同的调用
  • 如果参数中有一个Promise失败,那么Promise.all返回的Proise对象失败
static all(array) {  let result = []  let index = 0  return new MyPromise((resolve, reject) => {    // 执行for 循环有异步操作,循环没有期待异步操作。    // 如果index 等于 array的length 就调用resolve    function addData (key, value) {      result[key] = value;      index++       if (index === array.length) {        resolve(result)      }    }    // 须要判断是一般值, 还是Promise 对象    for (let i = 0; i < array.length; i++) {      let current = array[i];      if (current instanceof MyPromise) {        // promise 对象        current.then(value => addData(i, value), reason => reject(reason) )      } else {        // 一般值        addData(i, array[i])      }    }  })}

测试一下

function p1() {  return new MyPromise((resolve, reject) => {    setTimeout(() => {      resolve('p1')    }, 1000)  })}function p2() {  return new MyPromise((resolve, reject) => {    setTimeout(() => {      resolve('p1')    }, 1000)  })}MyPromise.all(['a', 'b', p1(), p2(), 'c']).then(result => {  console.log(result)})// [ 'a', 'b', 'p1', 'p1', 'c' ]

Promise.resolve 办法实现

  • Promise.resolve的作用是将给定的值转换为Promise 对象, 也就是说Promise.resolve 的返回值就就是一个Promise对象,在返回的Promise 对象中会包裹给定的这个值
  • resolve 的外部, 会创立一个Promise 对象,并把这个值包裹在Promise对象中,而后把创立进去的Promise 对象最作为resolve的返回值,正是因为这样,咱们能力前面进行链式调用then办法, 通过then办法的胜利回调函数来拿到这个值, Promise.resolve也能够接管一个Promise 对象, 在Promise.resolve外部会判断给定的值是一般值还是 Promise 对象,如果是Promise对象的话,会一成不变把Promise 在作为Promise.resolve的返回值,所以能力在后在调用then办法,通过then办法胜利回调函数来拿到Promise对象的返回值
static resolve(value) {  if (value instanceof myPromise) return value;  return new MyPromise(resolve => resolve(value))}

测试一下

function p1() {  return new MyPromise((resolve, reject) => {    setTimeout(() => {      resolve('p1')    }, 1000)  })}MyPromise.resolve('大白菜').then(value => console.log(value))MyPromise.resolve(p1()).then(value => console.log(value))// 大白菜// p1

Promise.reject()

static reject(reason) {    return new MyPromise((resolve,reject) => reject(reason))}

Promise.finally办法实现

Promise.finally有两个特点

  • 无论以后这个Promise对象最终的状态是胜利还是失败,finally办法这个会回调函数始终都会执行一次
  • finally的前面能够链式调用then 办法来拿到以后这个Promise对象最终返回的后果
finally(callback) {  return this.then(value => {    callback();    return value  }, reason => {    callback();    throw reason  })}

测试一下

function p1() {  return new MyPromise((resolve, reject) => {    resolve('p1 reject')    // reject('p1 reject')  })}function p2() {  return new MyPromise((resolve, reject) => {    setTimeout(() => {      resolve('p2')    }, 2000)  })}p1().finally(() => {  console.log('finally');  // return p2();}).then(value => {  console.log(value);}, reason => {  console.log(reason);})// finally// p1 reject
  • finally 的回调函数中,其实能够在return 一个Promise 对象
  • return p2前面的then须要期待setTimeout之后执行
  • 借助resolve办法
  • 如果callback返回的是一般值,转换Promise对象, 期待Promise 对象执行实现,如果返回的是Promise 对象,还期待你执行实现,在返回value

优化下面的代码

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

测试一下

function p1() {  return new MyPromise((resolve, reject) => {    setTimeout(() => {      resolve('p1 resolve')    }, 2000)  })}function p2() {  return new MyPromise((resolve, reject) => {    resolve('p2 resolve')    // reject('p2 reject')  })}p2().finally(() => {  console.log('finally');  return p1()}).then(value => {  console.log(value);}, reason => {  console.log(reason);})// finally // 期待2s后执行 输入p2 resolve

Promise.catch 办法实现

  • catch办法的作用是用来解决以后这个Promise 对象最终状态为失败的状况的,就是说当咱们调用then办法时候,咱们能够不传递失败回调, 如果不传失败回调,那么失败回调就能够被catch捕捉,从而去执行传入到catch办法的回调函数
  • 只须要在catch办法外部去调用then办法就能够了
catch (failCallback) {  return this.then(undefind, failCallback);}

测试一下

function p1() {  return new MyPromise((resolve, reject) => {    // resolve('大白菜~~')    reject('error')  })}p1()  .then(value => console.log(value))  .catch(reason => console.log(reason))

Promise.race()

  • Promise.race只返回第一个执行结束的Promise的后果,无论后果是fullfilled还是rejected
static race(promises) {    return new MyPromise((resolve, reject) => {        if (promises.length === 0) {            return        } else {            for (let p of promises) {                MyPromise.resolve(p).then(value => {                    resolve(value)                }, reason => {                    reject(reason)                })            }           }    })}

测试一下

const MyPromise = require('./myPromise');let promise1 = new MyPromise((resolve, reject) => {  setTimeout(() => {    resolve('大白菜')  }, 2000)});let promise2 = new MyPromise((resolve, reject) => {  setTimeout(() => {    resolve('米糕')  }, 1000)});MyPromise.race([promise1, promise2]).then((value) => {  console.log(value);});// 米糕

残缺代码

const PENDING = 'pending'; // 期待const FULFILLED = 'fulfilled'; // 胜利const REJECTED = 'rejected'; // 失败class MyPromise {  constructor (executor) {    try {      executor(this.resolve, this.reject)    } catch (e) {      this.reject(e);    }  }  // promise 状态  status = PENDING;  // 胜利后的值  value = undefined;  // 失败后的值  reason = undefined;  // 胜利回调  successCallback = [];  // 失败后的回调  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.faliCallback && this.faliCallback(this.reason);    while (this.failCallback.length) this.failCallback.shift()();  }  then (successCallback, failCallback) {    // 依据标准,如果then的参数不是function,则咱们须要疏忽它, 让链式调用持续往下执行    successCallback = typeof successCallback === 'function' ? successCallback : value => value;    failCallback = typeof failCallback === 'function' ? failCallback : reason => { throw reason };    let promise2 = new MyPromise((resolve, reject) => {      // 判断状态      if (this.status === FULFILLED) {        setTimeout(() => {          try {            let x = successCallback(this.value);            // 判断x的是是一般值还是promise对象            // 如果是一般值, 间接调用resolve            // 如是是promise对象 查看promise对象返回的后果            // 在依据promise对象返回的后果 决定调用resovle还是reject            resolvePromise(promise2, x, resolve, reject)                     } catch (e) {            reject(e)          }        }, 0)      } else if (this.status === REJECTED) {        setTimeout(() => {          try {            let x = failCallback(this.reason);            resolvePromise(promise2, x, resolve, reject)          } catch (e) {            reject(e)          }        }, 0)      } else {        // 期待        // 将期待回调和失败回调存储起来        this.successCallback.push(() => {          setTimeout(() => {            try {              let x = successCallback(this.value);              resolvePromise(promise2, x, resolve, reject)            } catch (e) {              reject(e)            }          }, 0)        }) // 将胜利回调推入        this.failCallback.push(() => {          setTimeout(() => {            try {              let x = failCallback(this.reason);              resolvePromise(promise2, x, resolve, reject)            } catch (e) {              reject(e)            }          }, 0)        }) // 将失败回调推入      }    });    return promise2;  }  static all(array) {    let result = []    let index = 0    return new MyPromise((resolve, reject) => {      // 执行for 循环有异步操作,循环没有期待异步操作。      // 如果index 等于 array的length 就调用resolve      function addData (key, value) {        result[key] = value;        index++;        // 保障all的每一项都执行完了        if (index === array.length) {          resolve(result);        }      }      // 须要判断是一般值, 还是Promise 对象      for (let i = 0; i < array.length; i++) {        let current = array[i];        if (current instanceof MyPromise) {          // promise 对象          current.then(value => addData(i, value), reason => reject(reason));        } else {          // 一般值          addData(i, array[i])        }      }    })  }  static resolve(value) {    if (value instanceof MyPromise) return value;    return new MyPromise(resolve => resolve(value))  }  static reject(reason) {    return new MyPromise((resolve,reject) => reject(reason))  }  static race(promises) {    return new MyPromise((resolve, reject) => {      if (promises.length === 0) {        return      } else {        for (let p of promises) {          MyPromise.resolve(p).then(value => {            resolve(value)          }, reason => {            reject(reason)          })        }         }    })  }  // finally链式调用返回Promise  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);  }}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(resolve, reject)  } else {    // 一般值    resolve(x)  }}module.exports = MyPromise;

总结

以上就是对Promise的实现的整个过程,咱们首先从一个简略Promise的应用实例开始,对Promise的外围进行了剖析,依据剖析咱们实现了大抵的一个构造,而后依据Promise A+标准一步一步的进行填充代码。次要实现了

  • Promise 异步逻辑
  • 实现then 办法屡次调用增加多个处理函数
  • Promise.then()办法链式调用
  • Promise.then()参数为可选参数
  • Promise.all()
  • Promise.resolve()
  • Peomise.reject()
  • Promise.finally()
  • Promise.catch()
  • Promise.rece()

感激大家

最初感谢您花贵重的工夫浏览这篇内容,如果你感觉这篇内容对你有帮忙的话,就给本文点个赞吧,
(感激大家的激励与反对????????????)

参考

Promise A+标准

Promise源码实现

9k字 | Promise/async/Generator实现原理解析