新闻中心

手写一个符合Promises/A+规范的Promise_j*ascript进阶

2025-11-03
浏览次数:
返回列表
答案:文章实现了一个符合Promises/A+规范的简易Promise,包含三种状态(pending、fulfilled、rejected)、构造函数、then方法链式调用、resolvePromise解析逻辑及静态resolve/reject方法,通过queueMicrotask处理异步回调,支持Promise链式传递与错误捕获。

手写一个符合promises/a+规范的promise_javascript进阶

实现一个符合 Promises/A+ 规范的 Promise 并不是一件简单的事,但通过一步步拆解核心逻辑,我们可以手写一个基本符合规范的简易版本。下面是一个简化但关键流程正确的 Promise 实现,帮助你深入理解其工作机制。

Promise 的三种状态

根据 Promises/A+ 规范,Promise 有三种状态:

  • pending:初始状态,未 fulfilled 或 rejected
  • fulfilled:成功状态,不可逆
  • rejected:失败状态,不可逆

状态一旦从 pending 变为 fulfilled 或 rejected,就不能再改变。

Promise 构造函数实现

我们从构造函数开始,接收一个执行器函数(executor),并初始化状态和值。

function MyPromise(executor) {
  this.status = 'pending';
  this.value = undefined;
  this.reason = undefined;

  // 存储 then 注册的成功和失败回调
  this.onFulfilledCallbacks = [];
  this.onRejectedCallbacks = [];

  const resolve = (value) => {
    if (this.status === 'pending') {
      this.status = 'fulfilled';
      this.value = value;
      // 执行所有成功的回调
      this.onFulfilledCallbacks.forEach(fn => fn());
    }
  };

  const reject = (reason) => {
    if (this.status === 'pending') {
      this.status = 'rejected';
      this.reason = reason;
      // 执行所有失败的回调
      this.onRejectedCallbacks.forEach(fn => fn());
    }
  };

  try {
    executor(resolve, reject);
  } catch (error) {
    reject(error); // 如果执行器出错,直接 reject
  }
}

then 方法的实现

then 方法是 Promise 的核心,用于注册成功和失败的回调,并返回一个新的 Promise,支持链式调用。

OneStory OneStory

OneStory 是一款创新的AI故事生成助手,用AI快速生成连续性、一致性的角色和故事。

OneStory 319 查看详情 OneStory
MyPromise.prototype.then = function(onFulfilled, onRejected) {
  // 处理回调可选的情况
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
  onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };

  // 返回一个新的 Promise
  const promise2 = new MyPromise((resolve, reject) => {
    if (this.status === 'fulfilled') {
      queueMicrotask(() => {
        try {
          const x = onFulfilled(this.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
    }

    if (this.status === 'rejected') {
      queueMicrotask(() => {
        try {
          const x = onRejected(this.reason);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
    }

    // 如果还是 pending,先缓存回调函数
    if (this.status === 'pending') {
      this.onFulfilledCallbacks.push(() => {
        queueMicrotask(() => {
          try {
            const x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      });

      this.onRejectedCallbacks.push(() => {
        queueMicrotask(() => {
          try {
            const x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      });
    }
  });

  return promise2;
};

resolvePromise 辅助函数

这个函数处理 x 的情况,判断它是否是 Promise,决定如何解析并 resolve 或 reject promise2。

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise'));
  }

  let called = false; // 防止多次调用 resolve/reject

  if (x != null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      const then = x.then;

      if (typeof then === 'function') {
        // 认为是 Promise 类型
        then.call(
          x,
          y => {
            if (called) return;
            called = true;
            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);
  }
}

静态方法:resolve 和 reject

提供快捷方式创建已解决或已拒绝的 Promise。

MyPromise.resolve = function(value) {
  return new MyPromise((resolve) => resolve(value));
};

MyPromise.reject = function(reason) {
  return new MyPromise((resolve, reject) => reject(reason));
};

使用示例

测试我们实现的 Promise:

new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('Hello');
  }, 1000);
})
.then(value => {
  console.log(value); // 1秒后输出 Hello
  return value + ' World';
})
.then(value => {
  console.log(value); // 输出 Hello World
});

基本上就这些。这个实现覆盖了 Promises/A+ 的核心机制:状态管理、异步任务队列(使用 queueMicrotask)、then 的链式调用和 resolvePromise 的递归解析。虽然省略了一些边界检查和更复杂的兼容逻辑,但它能帮助你理解 Promise 背后的运行原理。

以上就是手写一个符合Promises/A+规范的Promise_j*ascript进阶的详细内容,更多请关注其它相关文章!


# 三种  # 鄂州推广品牌营销费用  # 深圳seo外包公司费用  # 鼓楼区专业网站推广公司  # 濮阳网站建设全攻略  # 太原洗发水网站排名优化  # 武隆的知名网站建设  # 本钢钢材销售网站建设  # 可信的泉州seo咨询  # 2017网站优化方法  # 企业网站建设方讯  # 多线程  # 用它  # javascript  # 数据结构  # 可选  # 有哪些  # 进阶  # 递归  # 回调  # 链式  # 异步任务  # ai  # 回调函数  # java 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: Golang如何实现简单的Web表单_Golang表单提交与验证处理方法  QQ网页版官方账号入口 QQ网页版网页版登录指南  mysql如何设置表访问权限_mysql表访问权限配置  Golang如何使用bytes.Split分割字节切片_Golang bytes切片分割方法  sublime怎么设置启动时打开的窗口_sublime会话管理与热退出  如何使用纯J*aScript判断Input元素是否在特定类容器内  解决 MongoDB 聚合查询中对象数组 _id 匹配问题  格力空气能E5故障代码是什么情况_格力空气能E5代码解析与应对措施  MAC怎么让Dock栏只显示当前运行的应用_MAC终端命令实现极简Dock栏  Win10怎么制作U盘启动盘 Win10系统安装U盘制作教程【详解】  Lar*el Form Request中唯一性验证在更新操作中的正确实现  抖音网页版快捷访问 抖音网页版网页版入口操作教程  使用 Pandas 高效处理 .dat 文件:数据清洗与数值计算实战  AO3最新镜像入口 Archive of Our Own官方平台访问  Python大型XML文件高效流式解析教程  魅族17怎样用浏览器译外语网页_iPhone魅族17浏览器译外语网页【即时翻译】  CSS子选择器:如何区分并样式化嵌套列表的子层级  Python异步编程实践:使用Binance API构建实时交易数据流  TypeScript/J*aScript:高效查找数组中首个唯一ID对象  J*a里如何实现线程安全的懒加载单例_懒加载单例实现方法解析  J*aScript中localStorage数据的获取、清洗与格式化教程  Go语言中Map存储的结构体如何调用指针方法:深入解析与实践  PHP 枚举:根据字符串获取枚举案例的策略与实现  响应式CSS Grid布局:优化网格项在小屏幕下的堆叠与宽度适配  三星GalaxyZFold5怎样在相册制作折叠屏分镜_iPhone三星GalaxyZFold5相册制作折叠屏分镜【创意编辑】  Composer的 "licenses" 命令如何帮助你遵守开源协议_检查项目依赖的许可证合规性  小红书商家版怎样在笔记嵌入商品卡路径_小红书商家版在笔记嵌入商品卡路径【挂载教程】  手机CPU怎么影响游戏体验_手机CPU对游戏性能的影响分析  QQ邮箱官方网站登录入口_QQ邮箱网页版在线使用  今日头条怎么同步内容到抖音_今日头条内容同步到抖音教程  在命令行怎么运行html项目_命令行运行html项目方法【教程】  AO3最新入口2025公告_AO3中文官网合集  AO3官方可用镜像 Archive of Our Own网页版最新入口  夸克浏览器网页版最新地址 夸克浏览器官方入口合集  PowerPoint如何制作滚动字幕结尾彩蛋_PowerPoint路径动画实现平滑滚动字幕效果  MAC怎么在地图App里使用“四处看看”_MAC体验部分城市的3D实景街景  cad怎么合并重叠的线段_cad清理重复重叠线条的操作方法  taptap防沉迷怎么解除 taptap解除健康系统限制说明【2025最新】  探索高级语言到C/C++的转译路径:以Go为例及内存管理策略  PrimeNG Sidebar背景色自定义指南:CSS覆盖与主题化实践  PHP高效扁平化嵌套数组:使用array_merge与数组解包操作符  高德地图公交到站提醒失败如何解决 高德提醒权限设置  Win10文件资源管理器“此电脑”分组怎么关 Win10恢复经典视图【技巧】  在J*a中如何使用BigDecimal进行高精度计算_BigDecimal类应用指南  网易大神怎么保存别人动态的图片_网易大神动态图片保存方法  必由学在线入口 必由学网页版快速登录入口  知音漫客正版漫画平台_知音漫客官网账号登录  《北京人工智能产业白皮书(2025)》发布:全年核心产值预计突破 4500 亿元  海量存储:机器视觉智能化的核心基石  豆包手机助手发布技术预览版:直接嵌入手机系统!努比亚样机发售 

搜索