promise简单实现

52 阅读2分钟

promise 解决了什么问题

promise 主要是为了解决异步编程中,回调函数嵌套过多代码难以维护的问题,主要采用链式调用的方式进行解决。解决了异步发生异常时统一的异步异常处理的问题。另外ES6还通过扩展方法,all allsettled 以及 race解决了并发编程的问题,基于这几个方法,可以更简单的实现asynPool这种方法,对页面的过多请求进行控制

promise基本概念

  • promise有三个状态,pending fulfilled rejected,其中pending只可以变为fulfilled 或者 rejected,且状态不可逆
  • 每个promise对象都有一个then方法,接受两个函数,onFulfilled 和 onRejected,一个是成功时执行,一个是失败时执行
  • Promise的构造函数接受一个exectur函数,这个函数是同步执行的,这个函数接受两个参数,resolve和reject,负责更改promise的状态,resolve传入的值为value,会传递至onFulfilled中执行,reject传入的值为reason,会传入onRejected执行,另外,如果exectur函数执行过程中报错,也会传递至onRejected执行
  • promise的then方法如果返回一个promise,会将返回的promise的结果传递至then的onFulfilled和onRejected中,走哪个函数取决于返回的promise是成功还是失败
  • promise的onRejected如果捕获了异常,且onRejected中没有报错,没有返回失败状态的Promise,则会走到下一个then的onFulfilled中

promise的实现

Promise的实现基本上可以按照三步走,分别是同步版本的实现,异步版本的实现,以及当返回值是promise时如何处理,那我们就一步一步来吧

  • 同步版本的实现
const state = { // Promise的基本状态
  pending: "PENDING",
  fulfilled: "FULFILLED",
  rejected: "REJECTED",
};
class Promise {
  state = state.pending;
  value = undefined;
  reason = undefined;
  constructor(exectur) {
    const resolve = (value) => {
      if (this.state === state.pending) {
        this.value = value;
        this.state = state.fulfilled;
      }
    };
    const reject = (reason) => {
      if (this.state === state.pending) {
        this.reason = reason;
        this.state = state.rejected;
      }
    };
    exectur(resolve, reject);
  }

  then(onFufilled, onRejected) {
    if (this.state === state.fulfilled) {
      onFufilled(this.value);
    }

    if (this.state === state.rejected) {
      onRejected(this.reason);
    }
  }
}
export default Promise;
  • 异步版本的实现,异步的实现主要是借助了发布订阅,在resolve时将then方法储存的成功或者失败函数批量执行
const state = {
  pending: "PENDING",
  fulfilled: "FULFILLED",
  rejected: "REJECTED",
};
class Promise {
  state = state.pending;
  value = undefined;
  reason = undefined;
  fulfilledCallbacks = [];
  rejectedCallbacks = [];
  constructor(exectur) {
    const resolve = (value) => {
      if (this.state === state.pending) {
        this.value = value;
        this.state = state.fulfilled;
        this.fulfilledCallbacks.forEach((fn) => fn());
      }
    };
    const reject = (reason) => {
      if (this.state === state.pending) {
        this.reason = reason;
        this.state = state.rejected;
        this.rejectedCallbacks.forEach((fn) => fn());
      }
    };
    exectur(resolve, reject);
  }

  then(onFufilled, onRejected) {
    const promise = new Promise((resolve, reject) => {
      if (this.state === state.fulfilled) {
        const x = onFufilled(this.value);
      }

      if (this.state === state.rejected) {
        const x = onRejected(this.reason);
      }

      if (this.state === state.pending) {
        this.fulfilledCallbacks.push(() => {
            const x = onFufilled(this.value);
        });
        this.rejectedCallbacks.push(() => {
            const x = onRejected(this.reason);
        });
      }
    });

    return promise;
  }
}
export default Promise;
  • then中返回Promise时如何处理
const state = {
  pending: "PENDING",
  fulfilled: "FULFILLED",
  rejected: "REJECTED",
};
class Promise {
  state = state.pending;
  value = undefined;
  reason = undefined;
  fulfilledCallbacks = [];
  rejectedCallbacks = [];
  constructor(exectur) {
    const resolve = (value) => {
      if (this.state === state.pending) {
        this.value = value;
        this.state = state.fulfilled;
        this.fulfilledCallbacks.forEach((fn) => fn());
      }
    };
    const reject = (reason) => {
      if (this.state === state.pending) {
        this.reason = reason;
        this.state = state.rejected;
        this.rejectedCallbacks.forEach((fn) => fn());
      }
    };
    exectur(resolve, reject);
  }

  then(onFufilled, onRejected) {
    const promise = new Promise((resolve, reject) => {
      if (this.state === state.fulfilled) {
        process.nextTick(() => {
          const x = onFufilled(this.value);
          resolvePromise(promise, x, resolve, reject);
        });
      }

      if (this.state === state.rejected) {
        process.nextTick(() => {
          const x = onRejected(this.reason);
          resolvePromise(promise, x, resolve, reject);
        });
      }

      if (this.state === state.pending) {
        this.fulfilledCallbacks.push(() => {
          process.nextTick(() => {
            const x = onFufilled(this.value);
            resolvePromise(promise, x, resolve, reject);
          });
        });
        this.rejectedCallbacks.push(() => {
          process.nextTick(() => {
            const x = onRejected(this.reason);
            resolvePromise(promise, x, resolve, reject);
          });
        });
      }
    });

    return promise;
  }
}

function resolvePromise(promise, x, resolve, reject) {
  if (promise === x) {
    throw new TypeError("123");
  }
  if ((typeof x === "object" && x != null) || typeof x === "function") {
    const then = x.then;
    if (typeof then === "function") {
      then.call(
        x,
        (y) => {
          resolve(y);
        },
        (r) => {
          reject(r);
        }
      );
    }
  }
  resolve(x);
}
export default Promise;