promise

在开发中,常常须要用到promise,promise具备很多个性,这一次将对promise个性进行总结,并从零写一个promise。

步骤一

  • Promise特点

    • 1,创立时须要传递一个函数,否则会报错
    • 2,会给传入的函数设置两个回调函数
    • 3,刚创立的Promise对象状态是pending
class MyPromise {  constructor(handle) {    // 3,刚创立的Promise对象状态是pending    this.status = "pending";    // 1,创立时须要传递一个函数,否则会报错    if (!this._isFunction(handle)) {      throw new Error("请传入一个函数");    }    // 2,会给传入的函数设置两个回调函数    handle(this._resolve.bind(this), this._reject.bind(this))  }  _resolve() {  }  _reject() {  }  _isFunction(fn) {    return typeof fn === "function";  }}

步骤二

  • Promise特点

    • 4,状态一旦产生扭转就不可再次扭转
    • 5,能够通过then来监听状态的扭转

      • 5.1,如果创立监听时,状态曾经扭转,立刻执行监听回调
      • 5.2,如果创立监听时,状态未扭转,会等状态扭转后执行
      • 5.3,同一promise对象能够增加多个then监听,状态扭转时依照注册程序顺次执行
// 定义常量保留对象的状态const PENDING = "pending";const FULFILLED = "fulfilled";const REJECTED = "rejected";class MyPromise {  constructor(handle) {    // 3,刚创立的Promise对象状态是pending    this.status = PENDING;    // 胜利回调的值    this.value = undefined;    // 失败回调的值    this.reason = undefined;    // 注册的胜利回调    this.onResolvedCallbacks = [];    // 注册的失败回调    this.onRejectedCallbacks = [];    // 1,创立时须要传递一个函数,否则会报错    if (!this._isFunction(handle)) {      throw new Error("请传入一个函数");    }    // 2,会给传入的函数设置两个回调函数    handle(this._resolve.bind(this), this._reject.bind(this))  }  _resolve(value) {    // 4,状态一旦产生扭转就不可再次扭转    if (this.status === PENDING) {      this.status = FULFILLED;      this.value = value;      // 5.3,同一promise对象能够增加多个then监听,状态扭转时依照注册程序顺次执行      this.onResolvedCallbacks.forEach(fn => fn(this.value));    }  }  _reject(reason) {    // 4,状态一旦产生扭转就不可再次扭转    if (this.status === PENDING) {      this.status = REJECTED;      this.reason = reason;      // 5.3,同一promise对象能够增加多个then监听,状态扭转时依照注册程序顺次执行      this.onRejectedCallbacks.forEach(fn => fn(this.reason));    }  }  then(onResolved, onRejected) {    // 判断有没有传入胜利的回调    if (this._isFunction(onResolved)) {      // 5.1,如果创立监听时,状态曾经扭转,立刻执行监听回调      if (this.status === FULFILLED) {        onResolved(this.value);      }    }    // 判断有没有传入失败的回调    if (this._isFunction(onRejected)) {      // 5.1,如果创立监听时,状态曾经扭转,立刻执行监听回调      if (this.status === REJECTED) {        onRejected(this.reason);      }    }    // 5.2,如果创立监听时,状态未扭转,会等状态扭转后执行    if (this.status === PENDING) {      if (this._isFunction(onResolved)) {        this.onResolvedCallbacks.push(onResolved);      }      if (this._isFunction(onRejected)) {        this.onRejectedCallbacks.push(onRejected);      }    }  }  _isFunction(fn) {    return typeof fn === "function";  }}

详解then办法

  • 接管两个参数:胜利回调,失败回调
  • 如果promise失败了,然而没有注册失败监听,就会报错
  • then办法每次执行结束都会返回一个新的Promise对象

    • 如果then办法只有胜利回调

      • 则它返回的promise的状态会继承以后promise的状态。
      • 如果以后promise的状态为胜利:新promise的值为以后then的胜利回调的返回值。
      • 如果以后promise的状态为失败:新的promise没有失败监听,则会报错
    • 如果then办法同时蕴含胜利回调、失败回调
    • 则它返回的promise的状态都为胜利,且值为胜利或者失败回调的返回值。
  • 回调函数的返回值

    • 如果then办法的胜利/失败回调返回的是promise对象

      • 则then办法返回的新的promise对象的状态由新promise的外部决定。
      • 且值为新promise的内resolve/reject函数传递的参数。
    • 如果then办法的胜利/失败回调返回的是一般数据类型

      • 则then办法返回的新的promise对象的状态都为胜利。
      • 且值为胜利/失败回调的返回值,即都会传递给新的promise对象胜利的回调。
    • 如果then办法的胜利/失败回调没有返回值

      • 同返回一般数据类型
  • 失败回调函数

    • 能够捕捉上一个promise对象的then办法中胜利回调函数执行时的异样

参考 前端进阶面试题具体解答

then(onResolved, onRejected) {    return new MyPromise((nextResolve, nextReject) => {      // 1.判断有没有传入胜利的回调      if (this._isFunction(onResolved)) {        // 2.判断以后的状态是否是胜利状态        if (this.status === FULFILLED) {          try {            // 拿到上一个promise胜利回调执行的后果            let result = onResolved(this.value);            // console.log("result", result);            // 判断执行的后果是否是一个promise对象            if (result instanceof MyPromise) {              result.then(nextResolve, nextReject);            } else {              // 将上一个promise胜利回调执行的后果传递给下一个promise胜利的回调              nextResolve(result);            }          } catch (e) {            nextReject(e);          }        }      }      // 1.判断有没有传入失败的回调      // if(this._isFunction(onRejected)){      try {        // 2.判断以后的状态是否是失败状态        if (this.status === REJECTED) {          let result = onRejected(this.reason);          if (result instanceof MyPromise) {            result.then(nextResolve, nextReject);          } else {            nextResolve(result);          }        }      } catch (e) {        nextReject(e);      }      // }      // 2.判断以后的状态是否是默认状态      if (this.status === PENDING) {        if (this._isFunction(onResolved)) {          // this.onResolvedCallback = onResolved;          this.onResolvedCallbacks.push(() => {            try {              let result = onResolved(this.value);              if (result instanceof MyPromise) {                result.then(nextResolve, nextReject);              } else {                nextResolve(result);              }            } catch (e) {              nextReject(e);            }          });        }        // if(this._isFunction(onRejected)){        // this.onRejectedCallback = onRejected;        this.onRejectedCallbacks.push(() => {          try {            let result = onRejected(this.reason);            if (result instanceof MyPromise) {              result.then(nextResolve, nextReject);            } else {              nextResolve(result);              nextReject();            }          } catch (e) {            nextReject(e);          }        });        // }      }    });}

详解catch办法

  • 其实是then办法的失败回调函数的语法糖
  • 如果须要同时应用then和catch办法,必须应用链式编程,不然会报错
  • 能够捕捉上一个promise对象的then办法中胜利回调函数执行时的异样
catch(onRejected) {    return this.then(undefined, onRejected);}

为啥应用catch时最好应用链式编程

  • 因为then办法只有胜利回调,所以p2的状态会继承p1
  • 又因为p2的状态为失败,且没有对p2进行失败监听,所以报错
let p1 = new Promise(function (resolve, reject) {  // resolve();  reject();});let p2 = p1.then(function () {  console.log("胜利");});p1.catch(function () {  console.log("失败1");});

Promise.all()

  • Promise.all(params)特点

    • 参数为一个数组,且数组元素为promise类型数据
    • 返回值为一个promise,

      • 如果所有promise都执行胜利

        • 返回值为所有promise都胜利时返回的后果的汇合
      • 如果有一个promise执行失败了,则返回失败的promise
static all(list){    return new MyPromise(function (resolve, reject) {        let arr = [];        let count = 0;        for(let i = 0; i < list.length; i++){            let p = list[i];            p.then(function (value) {                // arr.push(value); 留神不要这样写,会导致后果程序不对                arr[i] = value                count++;                if(list.length === count){                    resolve(arr);                }            }).catch(function (e) {                reject(e);            });        }    });}

Promise.race()

  • Promise.race(params)特点

    • 参数为一个数组,且数组元素为promise类型数据
    • 返回值为一个promise,且返回值为第一个胜利或者失败的promise的值
static race(list){    return new MyPromise(function (resolve, reject) {        for(let p of list){            p.then(function (value) {                resolve(value);            }).catch(function (e) {                reject(e);            });        }    })}