手写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)
                    }
                })
        }
    })
}
相关推荐
恋猫de小郭2 分钟前
Flutter 的文字为什么比 SwiftUI 更细?问题主要在 Skia 的 256 项查找表里
android·前端·flutter
lexiangqicheng5 分钟前
前端高阶面试核心通关指南:深入解析Vue3与React18底层原理及性能优化
前端·面试·性能优化
怕浪猫5 分钟前
前端对接聊天 API:我用 React 做了一个比 ChatGPT 还好看的界面
前端·后端·面试
devilnumber8 分钟前
Java 内部迭代 vs 外部迭代:从原理到实战避坑
java·开发语言
程序员小孔.9 分钟前
基于 Spring Cloud + Vue 的 JEEWMS 开源仓储管理平台设计与实现
前端·javascript·vue.js·spring boot·spring cloud·开源
IT_陈寒10 分钟前
深入理解Python:核心原理与最佳实践
前端·人工智能·后端
杨运交14 分钟前
080-缓存模块-Spring Cache缓存键前缀设计与租户隔离实践
java·spring·缓存
创世虚拟世界14 分钟前
把 3D 虚拟世界拉到本地:vibe coding 的手感,是从看见自己那一行改动开始的
javascript·数据库·人工智能·3d·gitee·虚拟现实
\光辉岁月/18 分钟前
5.math类
java·开发语言
文丑颜不良啊19 分钟前
LeetCode76~100题目解析
java·leetcode