实现一个符合规范的Promise

2019-07-30  本文已影响0人  TerdShow
const PENDING = 'pengding';
const SUCCEED = 'fulfilled';
const FAILED = 'rejected';

function resolvePromise(promise2, x, resolve, reject) {
  var called;
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
  }
  if (typeof x === 'function' || (typeof x === 'object' && x != null)) {
    try {
      let then = x.then;
      if (typeof then === 'function') {
        if (called) return;
        called = true;
        then.call(x, y => {
          resolvePromise(promise2, y, resolve, reject);
        }, r => {
          reject(r);
        })
      } else {
        if (called) return;
        called = true;
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}

function isPromise(p) {
  if (typeof p === 'function' || (typeof p === 'object' && p != null)) {
    return typeof p.then === 'function'
  }
  return false;
}

class Promise {
  constructor(excutor) {
    this.state = PENDING;
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = value => {
      if (value instanceof Promise) {
        return value.then(resolve, reject);
      }
      if (this.state === PENDING) {
        this.state = SUCCEED;
        this.value = value;
        this.onResolvedCallbacks.forEach(cb => cb());
      }
    }
    const reject = reason => {
      if (this.state === PENDING) {
        this.state = FAILED;
        this.reason = reason;
        this.onRejectedCallbacks.forEach(cb => cb());
      }
    }
    try {
      excutor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
    onRejected = typeof onRejected === 'function' ? onRejected : err => {
      throw err
    };
    var promise2;
    promise2 = new Promise((resolve, reject) => {
      if (this.state === SUCCEED) {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.state === FAILED) {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.state === PENDING) {
        this.onResolvedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e)
            }
          })
        })
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e)
            }
          })
        })
      }
    })
    return promise2;
  }
  catch (errCallback) {
    return this.then(null, reject(errCallback));
  }
  static resolve(value){
    return new Promise((resolve, reject) => {
      resolve(value);
    })
  }
  static reject(reason){
    return new Promise((resolve, reject) => {
      reject(reason);
    })
  }
  static all(promises) {
    return new Promise((resolve, reject) => {
      let arr = [];
      let i = 0;
      const processData = (key, value) => {
        arr[key] = value;
        if (++i == promises.length) {
          resolve(arr);
        }
      }
      for (let i = 0; i < promises.length; i++) {
        let current = promises[i];
        if (isPromise(current)) {
          current.then(y => {
            processData(i, y)
          }, reject);
        } else {
          processData(i, current);
        }
      }
    })
  }
  static race(promises) {
    for (let i = 0; i < promises.length; i++) {
      let current = promises[i];
      if (isPromise(current)) {
        current.then(resolve, reject);
      } else {
        resolve(current);
      }
    }
  }
  static try(tryCallback) {
    return new Promise((resolve, reject) => {
      return Promise.resolve(tryCallback()).then(resolve, reject);
    })
  }
}
Promise.prototype.finally = (callback) => {
  return this.then(data => {
    return new Promise((resolve, reject) => {
      return resolve(callback());
    }).then(() => data);
  }, err => {
    return new Promise((resolve, reject) => {
      return resolve(callback());
    }).then(() => {
      throw err
    });
  })
}
module.exports = Promise;
上一篇下一篇

猜你喜欢

热点阅读