首页 > 试题广场 >

请设计一个浏览器中能使用的Promise模块。包含:实现源码

[问答题]
请设计一个浏览器中能使用的Promise模块。包含:实现源码,使用API,以及使用Demo。
// 定义三种状态、resolve和reject方法、then方法(onFulfilled、onRejected)
// 支持异步resolve.

function myPromise(constructor) {
    this.status = "pending" //定义初始状态
    this.value = undefined;//存储成功后的值
    this.reason = undefined;//存储失败的原因

    // 成功存放的数组
    this.onResolvedCallbacks = [];
    // 失败存放法数组
    this.onRejectedCallbacks = [];

    let resolve = value => {
        if (this.status === "pending") {
            console.log(1)
            this.status = "resolved";
            this.value = value;
            // 一旦resolve执行,调用成功数组的函数
            this.onResolvedCallbacks.forEach(fn => fn());
            console.log(2)
        }
    }
    let reject = reason => {
        if (this.status === "pending") {
            this.status = "rejected";
            this.reason = reason;
            // 一旦reject执行,调用失败数组的函数
            this.onRejectedCallbacks.forEach(fn => fn());
        }
    }
    //捕获构造异常
    try {
        constructor(resolve, reject);
    } catch (e) {
        reject(e);
    }
}

myPromise.prototype.then = function (onFulfilled, onRejected) {
    // 状态为fulfilled,执行onFulfilled,传入成功的值
    if (this.status === 'resolved') {
        onFulfilled(this.value);
    };
    // 状态为rejected,执行onRejected,传入失败的原因
    if (this.status === 'rejected') {
        onRejected(this.reason);
    };
    // 当状态status为pending时
    if (this.status === 'pending') {
        // onFulfilled传入到成功数组
        this.onResolvedCallbacks.push(() => {
            onFulfilled(this.value);
        })
        // onRejected传入到失败数组
        this.onRejectedCallbacks.push(() => {
            onRejected(this.reason);
        })
    }
}
发表于 2018-08-05 11:31:44 回复(0)
原创ES6写法,支持大部分API
const Status = {
  PENDING: Symbol('pending'),
  FUFILLED: Symbol('fulfilled'),
  REJECTED: Symbol('rejected'),
}
class MyPromise {
  constructor(callback) {
    this.Status = Status.PENDING;
    this.value = null;
    this.array = [];
    try {
      callback(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }
  resolve(value) {
    if (this.Status === Status.PENDING) {
      this.Status = Status.FUFILLED;
      this.value = value;
      setTimeout(() => {
        this.array.forEach(item => {
          item.onFulfilled(value);
        });
      });
    }
  }
  reject(reason) {
    if (this.Status === Status.PENDING) {
      this.Status = Status.REJECTED;
      this.value = reason;
      setTimeout(() => {
        this.array.forEach(item => {
          item.onRejected(reason);
        });
      });
    }
  }
  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function') {
      onFulfilled = () => this.value
    }
    if (typeof onRejected !== 'function') {
      onRejected = (err) => { throw err }
    }

    const promise = new MyPromise((resolve, reject) => {
      if (this.Status === Status.PENDING) {
        this.array.push({
          onFulfilled: (value) => {
            const result = onFulfilled(value);
            resolve(result);
          },
          onRejected: (reason) => {
            const result = onRejected(reason);
            resolve(result);
          }
        });
      }
      if (this.Status === Status.FUFILLED) {
        setTimeout(() => {
          try {
            const result = onFulfilled(this.value);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        });
      }
      if (this.Status === Status.REJECTED) {
        setTimeout(() => {
          try {
            const result = onRejected(this.value);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        });
      }
    });
    return promise;
  }
  catch(onRejected) {
    return this.then(null, onRejected)
  }
  finally(callback) {
    const MyPromise = this.constructor;
    return this.then(
      value => MyPromise.resolve(callback()).then(() => value),
      reason => MyPromise.resolve(callback()).then(() => { throw reason })
    );
  }
  static resolve(promise) {
    return new MyPromise((resolve, reject) => {
      if (promise instanceof MyPromise) {
        promise.then(resolve);
      } else {
        resolve(promise);
      }
    });
  }
  static reject(promise) {
    return new MyPromise((resolve, reject) => {
      reject(promise);
    });
  }
  static all(promises) {
    const values = [];
    return new MyPromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(value => {
          values.push(value);
          if (values.length === promises.length) {
            resolve(values);
          }
        }, reason => {
          reject(reason);
        });
      });
    });
  }
}


发表于 2020-09-03 15:29:20 回复(0)
const isFunction = variable => typeof variable === "function";

const __ = new WeakMap();
function get(that, key) {
  try {
    return __.get(that)[key];
  } catch (e) {
    console.error(e);
    return undefined;
  }
}
function set(that, key, value) {
  const lastValue = __.get(that);
  const newValue = {
    ...lastValue,
    [key]: value
  };
  __.set(that, newValue);
}

const promiseStatus = Symbol("status");
const promiseValue = Symbol("value");
const fulfilledCallbackQueue = Symbol("fulfilledCallbackQueue");
const rejectedCallbackQueue = Symbol("rejectedCallbackQueue");

const PENDING = Symbol("pending");
const FULFILLED = Symbol("fulfilled");
const REJECTED = Symbol("rejected");

const resolve = Symbol("resolve");
const reject = Symbol("reject");

class MyPromise {
  constructor(fn) {
    if (!isFunction(fn)) {
      throw new Error("MyPromise must accept a function as a parameter");
    }
    set(this, promiseStatus, PENDING);
    set(this, promiseValue, undefined);
    set(this, fulfilledCallbackQueue, []);
    set(this, rejectedCallbackQueue, []);
    try {
      fn(this[resolve].bind(this), this[reject].bind(this));
    } catch (e) {
      this[reject](e);
    }
  }

  [resolve](val) {
    const run = () => {
      if (get(this, promiseStatus) !== PENDING) return;
      const runFulfilled = value => {
        let cb;
        while ((cb = get(this, fulfilledCallbackQueue).shift())) {
          cb(value);
        }
      };
      const runRejected = error => {
        let cb;
        while ((cb = get(this, rejectedCallbackQueue).shift())) {
          cb(error);
        }
      };
      if (val instanceof MyPromise) {
        val.then(
          value => {
            set(this, promiseValue, value);
            set(this, promiseStatus, FULFILLED);
            runFulfilled(value);
          },
          err => {
            set(this, promiseValue, err);
            set(this, promiseStatus, REJECTED);
            runRejected(err);
          }
        );
      } else {
        set(this, promiseValue, val);
        set(this, promiseStatus, FULFILLED);
        runFulfilled(val);
      }
    };
    setTimeout(run, 0);
  }
  [reject](err) {
    if (get(this, promiseStatus) !== PENDING) return;
    const run = () => {
      set(this, promiseStatus, REJECTED);
      set(this, promiseValue, err);
      let cb;
      while ((cb = get(this, rejectedCallbackQueue).shift())) {
        cb(err);
      }
    };
    setTimeout(run, 0);
  }

  then(onFulfilled, onRejected) {
    return new MyPromise((onFulfilledNext, onRejectedNext) => {
      const fulfilled = value => {
        try {
          if (!isFunction(onFulfilled)) {
            onFulfilledNext(value);
          } else {
            const res = onFulfilled(value);
            if (res instanceof MyPromise) {
              res.then(onFulfilledNext, onRejectedNext);
            } else {
              onFulfilledNext(res);
            }
          }
        } catch (err) {
          onRejectedNext(err);
        }
      };
      const rejected = error => {
        try {
          if (!isFunction(onRejected)) {
            onRejectedNext(error);
          } else {
            const res = onRejected(error);
            if (res instanceof MyPromise) {
              res.then(onFulfilledNext, onRejectedNext);
            } else {
              onFulfilledNext(res);
            }
          }
        } catch (err) {
          onRejectedNext(err);
        }
      };
      switch (get(this, promiseStatus)) {
        case PENDING:
          const newFulfilledCallbackQueue = [
            ...get(this, fulfilledCallbackQueue),
            fulfilled
          ];
          set(this, fulfilledCallbackQueue, newFulfilledCallbackQueue);
          const newRejectedCallbackQueue = [
            ...get(this, rejectedCallbackQueue),
            rejected
          ];
          set(this, rejectedCallbackQueue, newRejectedCallbackQueue);
          break;
        case FULFILLED:
          fulfilled(get(this, promiseValue));
          break;
        case REJECTED:
          rejected(get(this, promiseValue));
          break;
      }
    });
  }
}
编辑于 2019-01-16 10:57:51 回复(0)