手写Promise

本文探讨如何手写Promise,遵循Promise A+规范,详细讲解then、catch、finally等核心方法的实现,并涵盖一些静态方法。
摘要由CSDN通过智能技术生成

Promise基本实现

包含Promise A+规范,then,catch,finally以及一些静态方法

/**
 * Promise基本用法
 * new Promise((resolve, reject) =>{})
 */


// 声明一些Promise状态的变量
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECT = 'rejected';

/**
 * 将任务放入微队列辅助方法
 * @param {Function} callback
 */
function runMicroTask(callback) {
  // node 环境处理
  if (process && process.nextTick) {
    process.nextTick(callback);
  } else if (MutationObserver) {
    // 浏览器环境处理,创建一个观察器,观察元素变化,如果有变化则将callback放入微队列
    const p = document.createElement('p');
    const observer = new MutationObserver(callback);
    observer.observe(p, {
      childList: true,
    });
    p.innerHTML = '1';
  } else {
    // 其他情况
    setTimeout(callback, 0);
  }
}

/**
 * 判断obj是否是一个promise
 * @param {Object} obj
 */
function isPromise(obj) {
  return !!(obj && typeof obj === 'object' && typeof obj.then === 'function');
}

class MyPromise {
  // 声明一个构造器,接受一个参数为函数
  constructor(executor) {
    // promise 状态默认为pending
    this._state = PENDING;
    // promise 返回的数据默认为undefined
    this._value = undefined;
    // promise 已决后存放后续处理函数的队列
    this._handlers = [];
    // 执行函数,传递两个参数resolve和reject
    try {
      executor(this._resolve.bind(this), this._reject.bind(this));
    } catch (error) {
      this._reject(error);
    }
  }

  /**
   * 标记当前任务完成
   * @param {any} data 完成任务后返回的数据
   */
  _resolve(data) {
    this._changeState(FULFILLED, data);
  }
  /**
   * 标记当前任务失败
   * @param {any} reason 任务失败后返回的原因
   */
  _reject(reason) {
    this._changeState(REJECT, reason);
  }

  /**
   * 更改任务状态
   * @param {string} state 状态
   * @param {any} value 数据
   */
  _changeState(state, value) {
    // promise 状态不可逆
    if (this._state !== PENDING) {
      return;
    }
    this._state = state;
    this._value = value;
    // 状态变化后也应该执行一次任务队列
    this._runHandlers();
  }

  /**
   * 实现Promise A+ 规范的then
   * @param {Function} onFulfilled Promise 成功后执行的函数
   * @param {Function} onRejected Promise 失败后执行的函数
   * @returns 返回一个Promise
   */
  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      // 将后续处理函数放入队列
      this._pushHandlers(onFulfilled, FULFILLED, resolve, reject);
      this._pushHandlers(onRejected, REJECT, resolve, reject);
      // 执行队列中的任务
      this._runHandlers();
    });
  }

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

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

  /**
   * 向队列中添加处理函数
   * @param {Function} executor
   * @param {String} state
   * @param {Function} resole
   * @param {Function} reject
   */
  _pushHandlers(executor, state, resolve, reject) {
    this._handlers.push({ executor, state, resolve, reject });
  }

  /**
   * 根据实际情况执行任务中的队列
   */
  _runHandlers() {
    // 如果当前Promise 的状态为pending 则不执行
    if (this._state === PENDING) {
      return;
    }
    // 否则遍历处理队列中的任务,处理之后将任务删掉避免重复执行
    while (this._handlers[0]) {
      this._runOneHandler(this._handlers[0]);
      this._handlers.shift();
    }
  }

  /**
   * 执行任务
   * @param {Object} param0 解构任务
   */
  _runOneHandler({ executor, state, resolve, reject }) {
    // 将任务放入微队列
    runMicroTask(() => {
      // 如果当前Promise 的状态和该任务的状态不一致则不执行
      if (this._state !== state) {
        return;
      }

      // 如果then中没有传递成功/失败后的处理函数,则和当前Promise 状态保持一致
      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);
      }
    });
  }


  /**
   * resolve静态方法实现
   * 1.如果data是一个promise
   * 2.如果data是一个promiselike,返回一个新的promise,状态和它保持一致
   * @param {*} data
   */
  static resolve(data) {
    if (data instanceof MyPromise) {
      return data;
    }
    return new MyPromise((resolve, reject) => {
      if (isPromise(data)) {
        data.then(resolve, reject);
      } else {
        resolve(data);
      }
    });
  }
  /**
   * reject静态方法实现
   * 1.直接返回一个promise,状态为reject
   * @param {*} reason
   */
  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason);
    });
  }
}


//测试...
new MyPromise((resolve, reject) => {
  console.log('myPromise excute');
  resolve(1);
}).then(
  (r) => {},
  (r) => {}
);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值