前端面试之路

「JavaScript」手写promise的实现

2019-07-28  本文已影响0人  ybrelax

知其然必知起所以然

Promise是用来处理异步的一种方案,以前如果在有碰到回调地狱的情况,代码看起来就非常的糟糕,有了promise之后,确实在整体上来说提上了不上,代码间接优美了很多。那么今天就来看一下promise是如何实现。

promise的基本结构

我们都知道promise有三种状态,pending, resolved, rejectd 这三种, 当pending的时候我们并不需要做什么,而resolved执行resolve函数,rejected 执行reject函数

所以可以描述出基本的结构

function Promisex(executor) {
  this.status = 'pending';
  this.value = undefined;
  this.reason = undefined;

  // 当Promise对象已经由pending状态改变为了成功态(resolved)或是失败态(rejected)就不能再次更改状态了
  var resolve = value => {
    // 这个地方说明状态为pending才能更新
    if (this.status === 'pending') {
      this.status = 'resolved';
      this.vaule = value
     }
   }
  var reject = reason => {
  if (this.status === 'pending') {
    this.status = reject
    this.reason = reason
   }
  };
  executor(resolve, reject)

接着再来定义一下then的结构

Promisex.prototype.then = function(onFullFilled, onRejected) {
    if (this.status === 'resolved') {
    onFullFilled(this.value);
} 

   if (this.status === 'rejected') {
      onRejected(this.reason);
}
}

上面可以很容易就展现了一个promise基本的形状

异步解决

你很可能发现上面的函数是同步的吗,如果你异步调用是不起作用的,那么如何解决异步方案--可以通过发布订阅者模式来进行

function Promisex() {
  ```` 省略
  this.onFullFilledFunc = [] // 这里存放成功回调
  this.onRejectedFunc = [] // 这里存放失败回调
}

Promisex.prototype.then = function (onFullFilled, onRejected) {
     // 如果是异步的话,这个地方进来还是pending 状态 
    if (typeof onFullFilled === 'function') {
      this.onFullFilledFunc.push(onFullFilled);
    }

    if (typeof onRejected === 'function') {
      this.onRejectedFunc.push(onRejected);
    }
}

这样就成功处理了promise的静态调用

链式调用

Promise链式调用的核心就把每个结果集再次包裹成一个Promise对象,然后循序调用

所以就可以来一个基本结果样貌

Promisex.prototye.then = function (onFullFilled, onRejected) {
 var promisex1 = new Promsiex( (resolve, reject) => {
    `````` 省略
})
return promisex1
}

如何实现链式调用呢?我们把这个过程抽象成一个函数,来分解

/**
 * 解析then返回值与新Promise对象
 * @param {Object} promise2 新的Promise对象
 * @param {*} x 上一个then的返回值
 * @param {Function} resolve promise2的resolve
 * @param {Function} reject promise2的reject
 */
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    reject(new TypeError('Promise发生循环引用'));
  }

  if (x !== null && (typeof x === 'object' || x === 'function')) {
    // 可能是个对象或者函数
    try {
      let then = x.then;
      if (typeof then === 'function') {
        then.call(
          x,
          y => {
            // resolve(y)
            //递归调用,传入y若是Promise对象,继续循环
            resolvePromise(promise2, y, resolve, reject);
          },
          r => {
            reject(r);
          },
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      reject(e);
    }
  } else {
    resolve(x);
  }
}

具体完整实现过程

function Promisex(executor) {
  this.status = 'pending';
  this.value = undefined;
  this.reason = undefined;
  this.onFullFilledFunc = []; // 保存成功回调状态
  this.onRejectedFunc = []; // 保存失败回调状态

  // 当Promise对象已经由pending状态改变为了成功态(resolved)或是失败态(rejected)就不能再次更改状态了
  var resolve = value => {
    // 这个地方说明状态为pending才能更新
    if (this.status === 'pending') {
      this.value = value;
      this.onFullFilledFunc.forEach(fun => {
        this.value= fun(this.value);
      });
      this.status = 'resolved';
    }
  };

  var reject = reason => {
    if (this.status === 'pending') {
      this.onRejectedFunc.forEach(fun => fun(reason));
      this.reason = reason;
      this.status = 'rejected'
    }
  };

  executor(resolve, reject);
}

Promisex.prototype.then = function(onFullFilled, onRejected) {
  if (this.status === 'pending') {
    if (typeof onFullFilled === 'function') {
      this.onFullFilledFunc.push(onFullFilled);
    }

    if (typeof onRejected === 'function') {
      this.onRejectedFunc.push(onRejected);
    }
    return this;
  }
  var promise2 = new Promisex((resolve, reject) => {
    if (this.status === 'resolved') {
      setTimeout(() => {
        try {
          let x = onFullFilled(this.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      }, 0);
    }
    if (this.status === 'rejected') {
      onRejected(this.reason);
    }
  });
  return promise2;
};

/**
 * 解析then返回值与新Promise对象
 * @param {Object} promise2 新的Promise对象
 * @param {*} x 上一个then的返回值
 * @param {Function} resolve promise2的resolve
 * @param {Function} reject promise2的reject
 */
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    reject(new TypeError('Promise发生循环引用'));
  }

  if (x !== null && (typeof x === 'object' || x === 'function')) {
    // 可能是个对象或者函数
    try {
      let then = x.then;
      if (typeof then === 'function') {
        then.call(
          x,
          y => {
            // resolve(y)
            //递归调用,传入y若是Promise对象,继续循环
            resolvePromise(promise2, y, resolve, reject);
          },
          r => {
            reject(r);
          },
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      reject(e);
    }
  } else {
    resolve(x);
  }
}

module.exports = Promisex;
上一篇下一篇

猜你喜欢

热点阅读