美文网首页前端面试之路
「JavaScript」手写promise的实现

「JavaScript」手写promise的实现

作者: ybrelax | 来源:发表于2019-07-28 09:42 被阅读0次

    知其然必知起所以然

    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;
    

    相关文章

      网友评论

        本文标题:「JavaScript」手写promise的实现

        本文链接:https://www.haomeiwen.com/subject/ejlrpqtx.html