手写promise

promise

javascript 复制代码
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";

function MyPromise(fn) {
  // 保存初始化状态
  var self = this;

  // 初始化状态
  this.state = PENDING;

  // 用于保存 resolve 或者 rejected 传入的值
  this.value = null;

  // 用于保存 resolve 的回调函数
  this.resolvedCallbacks = [];

  // 用于保存 reject 的回调函数
  this.rejectedCallbacks = [];

  // 状态转变为 resolved 方法
  function resolve(value) {
    // 判断传入元素是否为 Promise 值,如果是,则状态改变必须等待前一个状态改变后再进行改变
    if (value instanceof MyPromise) {
      return value.then(resolve, reject);
    }

    // 保证代码的执行顺序为本轮事件循环的末尾(可降级用setTimeout)
    queueMicrotask(() => {
      // 只有状态为 pending 时才能转变,
      if (self.state === PENDING) {
        // 修改状态
        self.state = RESOLVED;

        // 设置传入的值
        self.value = value;

        // 执行回调函数
        self.resolvedCallbacks.forEach(callback => {
          callback(value);
        });
        self.resolvedCallbacks=[]
      }
    });
  }

  // 状态转变为 rejected 方法
  function reject(value) {
    // 判断传入元素是否为 Promise 值,如果是,则状态改变必须等待前一个状态改变后再进行改变
    if (value instanceof MyPromise) {
      return value.then(resolve, reject);//手动拆包
    }
    // 保证代码的执行顺序为本轮事件循环的末尾
    queueMicrotask(() => {
      // 只有状态为 pending 时才能转变
      if (self.state === PENDING) {
        // 修改状态
        self.state = REJECTED;

        // 设置传入的值
        self.value = value;

        // 执行回调函数
        self.rejectedCallbacks.forEach(callback => {
          callback(value);
        });
        self.rejectedCallbacks=[]
      }
    });
  }

  // 将两个方法传入函数执行
  try {
    fn(resolve, reject);
  } catch (e) {
    // 遇到错误时,捕获错误,执行 reject 函数
    reject(e);
  }
}

MyPromise.prototype.then = function (onFulfilled, onReject) {
  // 可选参数兜底,不传时提供默认回调
  onFulfilled = typeof onFulfilled === "function" ? onFulfilled : val => val;
  onReject = typeof onReject === "function" ? onReject : err => { throw err };

  const self = this;
  // then 必须返回新 Promise 实现链式
  return new MyPromise((resolve, reject) => {
    // 成功封装函数(前一个promise成功时执行的函数)
    let fulfilled = () => {
      try {
        const result = onFulfilled(self.value);
        // 如果回调返回Promise,等待它完成再改变新promise状态
        result instanceof MyPromise ? result.then(resolve, reject) : resolve(result);
      } catch (err) {
        reject(err);
      }
    };
    // 失败封装函数(前一个promise失败时执行的函数)
    let rejected = () => {
      try {
        const result = onReject(self.value);
        result instanceof MyPromise ? result.then(resolve, reject) : resolve(result);
      } catch (err) {
        reject(err);
      }
    };

    switch (self.state) {
      case PENDING:
        self.resolvedCallbacks.push(fulfilled);
        self.rejectedCallbacks.push(rejected);
        break;
      case RESOLVED:
        fulfilled();
        break;
      case REJECTED:
        rejected();
        break;
    }
  })
};

promise.all

javascript 复制代码
function promiseAll(promises) {
  // 返回一个全新的Promise实例
  return new Promise(function(resolve, reject) {
    // 判断传入参数是否为数组,非数组直接抛出类型错误
    if (!Array.isArray(promises)) {
      throw new TypeError(`argument must be a array`)
    }
    // 记录已成功完成的Promise数量
    let resolvedCounter = 0;
    // 保存传入数组总长度
    let promiseNum = promises.length;
    // 存储所有Promise成功后的结果,下标与入参数组保持一致
    let resolvedResult = [];

     // 处理空数组特殊情况
        if (promiseNum === 0) {
            return resolve([])
        }

    // 循环遍历所有传入的任务
    for (let i = 0; i < promiseNum; i++) {
      // 使用Promise.resolve包装,兼容数组中传入普通值的情况
      Promise.resolve(promises[i])
        .then(value => {
          // 当前任务成功,成功计数+1
          resolvedCounter++;
          // 将结果存入对应下标,保证输出数组顺序和输入一致
          resolvedResult[i] = value;
          // 所有任务全部执行成功
          if (resolvedCounter == promiseNum) {
            // 把完整结果数组resolve出去
            resolve(resolvedResult)
          }
        }, error => {
          // 任意一个任务失败,直接reject失败原因,终止后续处理
          reject(error)
        })
    }
  })
}

promise.race

javascript 复制代码
Promise.race = function (args) {
  // 参数校验
  if (!Array.isArray(args)) {
    throw new TypeError('args must be an array')
  }
  return new Promise((resolve, reject) => {
    for (let i = 0, len = args.length; i < len; i++) {
      // 使用Promise.resolve包装,兼容普通值
      Promise.resolve(args[i]).then(resolve, reject)
    }
  })
}

promise.allSettled

javascript 复制代码
Promise.allSettled = function (promises) {
    // 参数校验
    if (!Array.isArray(promises)) {
        throw new TypeError('promises must be an array')
    }
    return new Promise((resolve) => {
        let count = 0
        const result = []
        const len = promises.length

        // 边界:空数组直接返回
        if (len === 0) {
            return resolve([])
        }

        for (let i = 0; i < len; i++) {
            // Promise.resolve 兼容普通非Promise值
            Promise.resolve(promises[i])
                .then((value) => {
                    result[i] = {
                        status: 'fulfilled',
                        value
                    }
                })
                .catch((reason) => {
                    result[i] = {
                        status: 'rejected',
                        reason
                    }
                })
                .finally(() => {
                    count++
                    // 全部处理完成
                    if (count === len) {
                        resolve(result)
                    }
                })
        }
    })
}
相关推荐
lbb 小魔仙2 小时前
MuMu 模拟器 6.0 硬核测评:这次升级确实不一样
java·开发语言·模拟器·mumu·硬核测评
LaughingZhu2 小时前
智能体经典范式构建:ReAct、Plan-and-Solve 与 Reflection
前端·react.js·前端框架
mONESY2 小时前
Node.js fs 文件系统模块 四种读写方案全解析
javascript·后端
H_HX1262 小时前
IDEA的下载和安装
java·intellij-idea·idea
AIGS0012 小时前
向量空间JBoltAI:本体语义如何跨越企业AI的语义鸿沟
java·大数据·人工智能·人工智能ai大模型应用
Larcher2 小时前
从回调地狱到优雅异步:Node.js 文件操作进化史
javascript·后端·架构
jsonbro2 小时前
手把手带你实现发布订阅模式
前端·vue.js·设计模式
一只猫的梦2 小时前
自动化模块 (Automation Module)
前端·chrome
r_oo_ki_e_2 小时前
Java 线程池
java·开发语言