Sunny-117 / js-challenges

✨✨✨ Challenge your JavaScript programming limits step by step

Home Page:https://juejin.cn/column/7244788137410560055

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

8. 完整实现Promise A+

Sunny-117 opened this issue · comments

commented
// 记录Promise的三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

/**
 * 运行一个微队列任务
 * 把传递的函数放到微队列中
 * @param {Function} callback
 */
function runMicroTask(callback) {
  // 判断node环境
  // 为了避免「变量未定义」的错误,这里最好加上前缀globalThis
  // globalThis是一个关键字,指代全局对象,浏览器环境为window,node环境为global
  if (globalThis.process && globalThis.process.nextTick) {
    process.nextTick(callback);
  } else if (globalThis.MutationObserver) {
    const p = document.createElement("p");
    const observer = new MutationObserver(callback);
    observer.observe(p, {
      childList: true, // 观察该元素内部的变化
    });
    p.innerHTML = "1";
  } else {
    setTimeout(callback, 0);
  }
}

/**
 * 判断一个数据是否是Promise对象
 * @param {any} obj
 * @returns
 */
function isPromise(obj) {
  return !!(obj && typeof obj === "object" && typeof obj.then === "function");
}

class MyPromise {
  /**
   * 创建一个Promise
   * @param {Function} executor 任务执行器,立即执行
   */
  constructor(executor) {
    this._state = PENDING; // 状态
    this._value = undefined; // 数据
    this._handlers = []; // 处理函数形成的队列
    try {
      executor(this._resolve.bind(this), this._reject.bind(this));
    } catch (error) {
      this._reject(error);
      console.error(error);
    }
  }

  /**
   * 向处理队列中添加一个函数
   * @param {Function} executor 添加的函数
   * @param {String} state 该函数什么状态下执行
   * @param {Function} resolve 让then函数返回的Promise成功
   * @param {Function} reject 让then函数返回的Promise失败
   */
  _pushHandler(executor, state, resolve, reject) {
    this._handlers.push({
      executor,
      state,
      resolve,
      reject,
    });
  }

  /**
   * 根据实际情况,执行队列
   */
  _runHandlers() {
    if (this._state === PENDING) {
      // 目前任务仍在挂起
      return;
    }
    while (this._handlers[0]) {
      const handler = this._handlers[0];
      this._runOneHandler(handler);
      this._handlers.shift();
    }
  }

  /**
   * 处理一个handler
   * @param {Object} handler
   */
  _runOneHandler({ executor, state, resolve, reject }) {
    runMicroTask(() => {
      if (this._state !== state) {
        // 状态不一致,不处理
        return;
      }

      if (typeof executor !== "function") {
        // 传递后续处理并非一个函数
        this._state === FULFILLED ? resolve(this._value) : reject(this._value);
        return;
      }
      try {
        const result = executor(this._value);
        if (isPromise(result)) {
          result.then(resolve, reject);
        } else {
          resolve(result);
        }
      } catch (error) {
        reject(error);
        console.error(error);
      }
    });
  }

  /**
   * Promise A+规范的then
   * @param {Function} onFulfilled
   * @param {Function} onRejected
   */
  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      this._pushHandler(onFulfilled, FULFILLED, resolve, reject);
      this._pushHandler(onRejected, REJECTED, resolve, reject);
      this._runHandlers(); // 执行队列
    });
  }

  /**
   * 仅处理失败的场景
   * @param {Function} onRejected
   */
  catch(onRejected) {
    return this.then(null, onRejected);
  }

  /**
   * 无论成功还是失败都会执行回调
   * @param {Function} onSettled
   */
  finally(onSettled) {
    return this.then(
      (data) => {
        onSettled();
        return data;
      },
      (reason) => {
        onSettled();
        throw reason;
      }
    );
  }

  /**
   * 更改任务状态
   * @param {String} newState 新状态
   * @param {any} value 相关数据
   */
  _changeState(newState, value) {
    if (this._state !== PENDING) {
      // 目前状态已经更改
      return;
    }
    this._state = newState;
    this._value = value;
    this._runHandlers(); // 状态变化,执行队列
  }

  /**
   * 标记当前任务完成
   * @param {any} data 任务完成的相关数据
   */
  _resolve(data) {
    this._changeState(FULFILLED, data);
  }

  /**
   * 标记当前任务失败
   * @param {any} reason 任务失败的相关数据
   */
  _reject(reason) {
    this._changeState(REJECTED, reason);
  }

}
commented

class myPromise {
constructor(executor) {//传入的函数(resolve,reject)=>{}
this.state = myPromise.PENDING
this.value = null
this.reason = null
this.onFulfilledFns = [] //异步回调队列
this.onRejectedFns = []
const resolve = value => {
if (this.state === myPromise.PENDING) {//只有在pendding才可修改状态
this.state = myPromise.FULFILLED
this.value = value
//执行异步回调
this.onFulfilledFns.forEach(fn => typeof fn === 'function' && fn())
}
}
const reject = reason => {
if (this.state === myPromise.PENDING) {//只有在pendding才可修改状态
this.state = myPromise.REJECTED
this.reason = reason

    this.onRejectedFns.forEach(fn => fn())
  }
}
executor(resolve, reject) //执行传入new promise的函数,执行resolve或reject

}
then(onFulfilled, onRejected) {//接收成功、失败的回调函数,或接收值, 值会透传
//处理值穿透
if (typeof onFulfilled !== 'function') onFulfilled = a => a
if (typeof onRejected !== 'function') {
onRejected = e => {
throw e
}
}
return new myPromise((resolve, reject) => {//返回new promise实例,链式调用
//执行微任务同步回调
if (this.state === myPromise.FULFILLED) {
// 封装execute
queueMicrotask(() => {
execute(onFulfilled, this.value, resolve, reject)//执行回调函数,将函数中的return用resolve包裹
})
} else if (this.state === myPromise.REJECTED) {
// 封装execute
queueMicrotask(() => execute(onRejected, this.reason, resolve, reject))
}
//执行异步回调,添加进数组,resolve时再调用函数
else {
this.onFulfilledFns.push(() =>
queueMicrotask(() =>
// 封装execute
execute(onFulfilled, this.value, resolve, reject)
)
)
this.onRejectedFns.push(() =>
queueMicrotask(() =>
// 封装execute
execute(onRejected, this.reason, resolve, reject)
)
)
}
})
}
}
function execute(cb, value, resolve, reject) {
try {
// 判断onFulfilled,onRejected返回值是否是Promise对象
const res = cb(value)
if (res instanceof myPromise) {
//如果是,那么新的Promise对象的状态就等于原来的Promise对象的状态
res.then(resolve, reject)
} else {
// 否则就是成功的状态
resolve(res)
}
} catch (e) {
reject(e)
}
}
myPromise.PENDING = 'pending'
myPromise.FULFILLED = 'fulfilled'
myPromise.REJECTED = 'rejected'

Promise A+规范要求obj是一个对象或函数,这样写是否是更合理一点
address: https://promisesaplus.com/#point-53

function isPromise(obj) {
  return !!(obj && (typeof obj === "object" || typeof obj === 'function') && typeof obj.then === "function");
}

请问这两边都需要执行队列中的函数吗?有点没太明白

then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      this._pushHandler(onFulfilled, FULFILLED, resolve, reject);
      this._pushHandler(onRejected, REJECTED, resolve, reject);
      this._runHandlers(); // 执行队列
    });
  }

_changeState(newState, value) {
    if (this._state !== PENDING) {
      // 目前状态已经更改
      return;
    }
    this._state = newState;
    this._value = value;
    this._runHandlers(); // 状态变化,执行队列
  }
commented

if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
// 如果 x 为对象或函数
try {
// 把 x.then 赋值给 then
var then = x.then;
} catch (e) {
// 如果取 x.then 的值时抛出错误 e ,则拒绝 promise
return reject(e);
}

    /**
     * 如果 then 是函数,将 x 作为函数的作用域 this 调用之。
     * 传递两个回调函数作为参数,
     * 第一个参数叫做 `resolvePromise` ,第二个参数叫做 `rejectPromise`
     */
    if (typeof then === 'function') {
        // 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
        let called = false; // 避免多次调用
        try {
            then.call(
                x,
                // 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
                y => {
                    if (called) return;
                    called = true;
                    resolvePromise(promise2, y, resolve, reject);
                },
                // 如果 rejectPromise 以据因 r 为参数被调用,拒绝 promise
                r => {
                    if (called) return;
                    called = true;
                    reject(r);
                }
            )
        } catch (e) {
            /**
             *  如果调用 then 方法抛出了异常 e
             * 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
             */
            if (called) return;
            called = true;
            // 拒绝 promise
            reject(e);
        }
    } else {
        如果 then 不是函数,以 x 为参数执行 promise
        resolve(x);
    }
commented
function Promise(executor) {
  this.state = "pending";
  this.value = undefined;
  this.reason = undefined;
  // 保存成功回调
  this.onResolvedCallbacks = [];
  // 保存失败回调
  this.onRejectedCallbacks = [];

  let _this = this;
  try {
    executor(resolve, reject);
  } catch (error) {
    reject(error);
  }

  function resolve(value) {
    if (_this.state === "pending") {
      _this.state = "resolved";
      _this.value = value;
      _this.onResolvedCallbacks.forEach((cb) => cb(value));
    }
  }
  function reject(reason) {
    if (_this.state === "pending") {
      _this.state = "rejected";
      _this.reason = reason;
      _this.onRejectedCallbacks.forEach((cb) => cb(reason));
    }
  }
}

Promise.prototype.then = function (onFulfilled, onRejected) {
  onFulfilled =
    typeof onFulfilled === "function" ? onFulfilled : (value) => value;
  onRejected =
    typeof onRejected === "function"
      ? onRejected
      : (err) => {
          throw err;
        };

  let promise2 = new Promise((resolve, reject) => {
    // 等待态判断,此时异步代码还未走完,回调入数组队列
    if (this.state === "pending") {
      this.onResolvedCallbacks.push(() => {
        queueMicrotask(() => {
          try {
            let x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      });

      this.onRejectedCallbacks.push(() => {
        queueMicrotask(() => {
          try {
            let x = onRejected(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      });
    }
    if (this.state === "resolved") {
      queueMicrotask(() => {
        try {
          let x = onFulfilled(this.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
    }
    if (this.state === "rejected") {
      queueMicrotask(() => {
        try {
          let x = onRejected(this.reason);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
    }
  });
  return promise2;
};

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    reject(new TypeError("请避免Promise循环引用"));
  }
  let called;
  if (x !== null && (typeof x === "object" || typeof x === "function")) {
    // 可能是个对象或是函数
    try {
      let then = x.then;
      if (typeof then === "function") {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            // 递归调用,传入y若是Promise对象,继续循环
            resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    // 普通值结束递归
    resolve(x);
  }
}
commented
class MyPromise {
  static PENDING = "pending";
  static FULFILLED = "fulfilled";
  static REJECTED = "rejected";
  constructor(executor) {
    this.status = MyPromise.PENDING;
    this.value = null;
    this.callbacks = [];
    executor(this.resolve.bind(this), this.reject.bind(this));
  }
  resolve(value) {
    this.status = MyPromise.FULFILLED;
    this.value = value;
    setTimeout(() => {
      this.callbacks.forEach((cb) => {
        cb.onFulfilled(this.value);
      });
    });
  }
  reject(value) {
    this.status = MyPromise.REJECTED;
    this.value = value;
    setTimeout(() => {
      this.callbacks.forEach((cb) => {
        cb.onRejected(this.value);
      });
    });
  }
  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== "function") onFulfilled = (value) => value;
    if (typeof onRejected !== "function") onRejected = (value) => value;
    return new MyPromise((resolve, reject) => {
      if (this.status === MyPromise.PENDING) {
        this.callbacks.push({
          onFulfilled: (value) => {
            const res = onFulfilled(value);
            this.resolvePromise(res, resolve, reject);
          },
          onRejected: (value) => {
            const res = onFulfilled(value);
            this.resolvePromise(res, resolve, reject);
          },
        });
      }
      if (this.status === MyPromise.FULFILLED) {
        setTimeout(() => {
          const res = onFulfilled(this.value);
          this.resolvePromise(res, resolve, reject);
        });
      }
      if (this.status === MyPromise.REJECTED) {
        setTimeout(() => {
          const res = onFulfilled(this.value);
          this.resolvePromise(res, resolve, reject);
        });
      }
    });
  }

  resolvePromise(res, resolve, reject) {
    try {
      // const res = onFulfilled(value);
      if (res instanceof MyPromise) {
        res.then(resolve, reject);
      } else {
        resolve(res);
      }
    } catch (error) {
      reject(error);
    }
  }
}

TypeScript 实现,包含 Promise/A+ 测试,可作参考:
https://github.com/YieldRay/r-promise