duyue6002 / Blog

:pencil2: Write here
http://duyue6002.github.io/Blog/#/
5 stars 1 forks source link

[总结] Promise 的实现 #23

Open duyue6002 opened 5 years ago

duyue6002 commented 5 years ago

构造函数主体

// Promise构造函数接收一个executor函数,executor函数执行完同步或异步操作后,调用它的两个参数resolve和reject
var promise = new Promise(function(resolve, reject) {
  /*
    如果操作成功,调用resolve并传入value
    如果操作失败,调用reject并传入reason
  */
})

构造函数框架如下:

function myPromise(executor) {
  let self = this;
  self.status = "pending";
  self.data = undefined;
  self.onResolvedCallback = [];
  self.onRejectedCallback = [];
  executor(resolve, reject);
}

添加捕错机制

function myPromise(executor) {
  let self = this;
  self.status = "pending";
  self.data = undefined;
  let onResolvedCallback = [];
  let onRejectedCallback = [];

  function resolve(value) {
    // TODO
  };

  function reject(reason) {
    // TODO
  };

  try {
    executor(resolve, reject);
  } catch (error) {
    reject(error);
  }
}

添加 resolve / reject 方法

  function resolve(value) {
    if (self.status === "pending") {
      self.status = "resolved";
      self.data = value;
      for (let i = 0; i < self.onResolvedCallback.length; i++) {
        self.onResolvedCallback[i](value);
      }
    }
  };

  function reject(reason) {
    if (self.status === "pending") {
      self.status = "rejected";
      self.data = reason;
      for (let i = 0; i < self.onRejectedCallback.length; i++) {
        self.onRejectedCallback[i](reason);
      }
    }
  };
duyue6002 commented 5 years ago

实现可以与其他类型promise混合使用

function resolvePromise(promise2, x, resolve, reject) {
  let then;
  let thenCalledOrThrow = false;
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise'))
  }
  if (x instanceof myPromise) {
    if (x.status === 'pending') {
      x.then(function(value) {
        resolvePromise(promise2, value, resolve, reject)
      }, reject)
    } else {
      x.then(resolve, reject)
    }
    return
  }
  if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {
    try {
      then = x.then
      if (typeof then === 'function') {
        then.call(x, function rs(y) {
          if (thenCalledOrThrow) return
          thenCalledOrThrow = true
          return resolvePromise(promise2, y, resolve, reject)
        }, function rj(r) {
          if (thenCalledOrThrow) return
          thenCalledOrThrow = true
          return reject(r)
        })
      } else {
        resolve(x)
      }
    } catch (error) {
      if (thenCalledOrThrow) return
      thenCalledOrThrow = true
      return reject(error)
    }
  } else {
    resolve(x)
  }
}
duyue6002 commented 5 years ago

实现then方法

myPromise.prototype.then = function(onResolved, onRejected) {
  let self = this;
  let promise2;
  onResolved = typeof onResolved === 'function' ? onResolved : function(v) {return v};
  onRejected = typeof onRejected === 'function' ? onRejected : function(r) {throw r};

  if (self.status === 'resolved') {
    return promise2 = new Promise(function(resolve, reject) {
      setTimeout(() => {
        try {
          let x = onResolved(self.data);
          resolvePromise(promise2, x, resolve, reject)
        } catch (error) {
          reject(error);
        }  
      });

    })
  }

  if (self.status === 'rejected') {
    return promise2 = new Promise(function(resolve, reject) {
      setTimeout(() => {
        try {
          let x = onRejected(self.data);
          resolvePromise(promise2, x, resolve, reject)
        } catch (error) {
          reject(error)
        }  
      });
    })
  }

  if (self.status === 'pending') {
    return promise2 = new Promise(function(resolve, reject) {
      self.onResolvedCallback.push(function(value) {
        try {
          let x = onResolved(value);
          resolvePromise(promise2, x, resolve, reject)
        } catch (error) {
          reject(error)
        }
      })

      self.onRejectedCallback.push(function(reason) {
        try {
          let x = onRejected(reason);
          resolvePromise(promise2, x, resolve, reject)
        } catch (error) {
          reject(error)
        }
      })
    })
  }
}