手写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)
                    }
                })
        }
    })
}
相关推荐
麻瓜生活睁不开眼6 小时前
Android16修改全局桌面视图边框四直角显示为弧边圆角
android·java·深度学习
dear_bi_MyOnly6 小时前
【MyBatis 操作数据库】
java·数据库·学习·mybatis·学习方法
2601_953720826 小时前
【计算机毕业设计】基于Spring Boot的心理健康咨询与评测系统的设计与实现
java·spring boot·后端
丈剑走天涯7 小时前
JDK 17 正式特性
java·开发语言
东方小月7 小时前
从零开发一个 Coding Agent(四):使用状态机校验大模型事件流
前端·人工智能·后端
圣光SG8 小时前
Java操作题练习(七)
java·开发语言·算法
Csvn8 小时前
🧩 ESM vs CJS 混用的 7 个「天坑」——从 TypeScript 编译到 Node 与浏览器
前端
Csvn8 小时前
🎯 Web 性能 API 集合:Performance Observer 的 5 个冷门妙用
前端
Csvn8 小时前
深入 React 闭包陷阱:从根源上理解并根治 stale closure
前端
whyfail8 小时前
前端学 Spring Boot(8):接口为什么越用越慢?
前端·spring boot·后端