如果手写一个promise还有问题就来看这篇文章

191 阅读4分钟

一、前言

作为面试中高频出现的面试题----手写一个符合Promise+规范的Promise.一开始是蒙的,完全没有思路,但是看过很多人的各种文章解析之后有了自己的思路。

其实手写几遍符合规范的promise之后,很多之前对于promise执行的疑惑就都一一解开了,有一种豁然开朗的感觉,其实我说的是在做event loop的题的时候,遇到promise人就傻了,但是更深入了解promise之后就很多问题迎刃而解。

二、关于一个Promise要有哪些注意的点,根据别人的文章,总结一下(参考别人思路并拓展加入一些自己的见解)

    1. new Promise时,需要传递一个 executor 执行器,执行器立刻执行
    1. executor 接受两个参数,分别是 resolve 和 reject
    1. promise 只能从 pending 到 rejected, 或者从 pending 到 fulfilled
    1. promise 的状态一旦确认,就不会再改变
    1. promise 都有 then 方法,then 接收两个参数,分别是 promise 成功的回调 onFulfilled, 和 promise 失败的回调 onRejected
    1. 如果调用 then 时,promise已经成功,则执行 onFulfilled,并将promise的值作为参数传递进去。如果promise已经失败,那么执行 onRejected, 并将 promise 失败的原因作为参数传递进去。如果promise的状态是pending,需要将onFulfilled和onRejected函数存放起来,等待状态确定后,再依次将对应的函数执行(发布订阅)
    1. then 的参数 onFulfilled 和 onRejected 可以缺省
    1. promise 可以then多次,promise 的then 方法返回一个 promise
    1. 如果 then 返回的是一个结果,那么就会把这个结果作为参数,传递给下一个then的成功的回调(onFulfilled)
    1. 如果 then 中抛出了异常,那么就会把这个异常作为参数,传递给下一个then的失败的回调(onRejected)
    1. 如果 then 返回的是一个promise,那么需要等这个promise,那么会等这个promise执行完,promise如果成功,就走下一个then的成功,如果失败,就走下一个then的失败

三、手撸promise


const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

function myPromise(excutor) {

  let self = this;
  // 一个promise要有这五个值
  self.status = PENDING;
  self.value = null;
  self.reason = null;
  // 当状态一直是PENDING 的时候需要存起来
  self.onFulfilledCallBacks = [];
  self.onRejectedCallBacks = [];


  // excutor 中 resolve 函数, value 为要传的值
  function resolve(value) {
    // 避免多次resolve
    if (self.status === PENDING) {
      self.value = value;
      self.status = FULFILLED;
      self.onFulfilledCallBacks.forEach(fn => fn());
    }
  }

  // excutor 中 reject 函数, reson 为要传的值
  function reject(reson) {
    // 避免多次 reject
    if (self.status === PENDING) {
      self.reason = reson;
      self.status = REJECTED;
      self.onRejectedCallBacks.forEach(fn => fn());
    }
  }

  // excutor立即执行
  try {
    excutor(resolve, reject);
  } catch(e) {
    reject(e);
  }

}

myPromise.prototype.then = function (onFulfilled, onRejected) {
  // 由于onFulfilled, onRejected可以缺省 所以一开始要判定下是否为可执行的函数
  // onFulfilled如果缺省的话默认执行一个返回传参的函数
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
  // onRejected如果缺省的话默认执行一个抛出reason的函数
  onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
  // 由于then函数本身是一个promise(能链式调用),所以新声明一个promise
  let self = this;
  let promise2 = new myPromise((resolve, reject) => {
    // 执行成功态
    if (self.status === FULFILLED) {
      // onFulfilled要放到异步里执行,这里是模拟用settimeout,实际上promise是在V8引擎里实现了异步
      setTimeout(() => {
        try {
          // x 为 onFulfilled的返回值
          let x = onFulfilled(self.value);
          // 递归调用 下个then(链式调用)
          resolvePromise(promise2, x, resolve, reject);
        } catch(e) {
          reject(e)
        }
      }, 0);
    }

    // 执行失败态
    if (self.status === REJECTED) {
      setTimeout(() => {
        try {
          // x 为 Reject 的返回值
          let x = onRejected(self.reason);
          // 递归调用 下个then(链式调用)
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e)
        }
      }, 0);
    }

    // 执行等待态
    if (self.status === PENDING) {
      // 如果是pending态 就先存起来
      self.onFulfilledCallBacks.push(() => {
        setTimeout(() => {
          try {
            // x 为 onFulfilled的返回值
            let x = onFulfilled(self.value);
            // 递归调用 下个then(链式调用)
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e)
          }
        }, 0);
      })

      self.onRejectedCallBacks.push(() => {
        setTimeout(() => {
          try {
            // x 为 Reject 的返回值
            let x = onRejected(self.reason);
            // 递归调用 下个then(链式调用)
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e)
          }
        }, 0);
      })
    }
  })

  return promise2;
}

function resolvePromise(promise2, x, resolve, reject) {
  let self = this;
  // 首先先判断下是否是调动promise2 本身,是的话就是循环调用
  if (promise2 === x) {
    return reject(new TypeError('chaining cycle'));
  }
  let called;
  if (typeof x === 'object' && x || typeof x === 'function') {
    // 里面递归调用了resolvePromise,所以还是用try catch包起来
    try {
      let then = x.then;
      if (typeof then === 'function') {
        console.log('x为promise------')
        then.call(x, y => {
          // 只能有一次终态
          if (called) return;
          called = true;
          // 继续递归
          resolvePromise(promise2, y, resolve, reject);
        }, r => {
          // 只能有一次终态
          if (called) return;
          called = true;
          reject(r);
        })
      } else {
        console.log('x为有值 值为function或x.then不为function时------')

        // 只能有一次终态
        if (called) return;
        called = true;
        resolve(x);
      }
    } catch(e) {
      // 只能有一次终态
      if (called) return;
      called = true;
      reject(e);
    }
    
  } else {
    console.log('x为undefined或者明确的值时 ------')
    resolve(x);
  }

}
 

后续补充例子。。理解代码的例子