新闻中心

手写Promise核心原理及源码实现_j*ascript技巧

2025-11-07
浏览次数:
返回列表
Promise 有 pending、fulfilled、rejected 三种状态,状态一旦改变不可逆;2. 通过 then 方法注册回调并返回新 Promise 实现链式调用;3. 回调异步执行,使用 queueMicrotask 模拟微任务;4. resolvePromise 函数处理 then 返回值,若为 Promise 则递归解析,否则直接 resolve;5. 需防止循环引用和多次调用,确保错误冒泡。

手写promise核心原理及源码实现_javascript技巧

Promise 是 J*aScript 中处理异步操作的核心机制,理解其底层原理有助于更好地掌握异步编程。下面从手写一个简易但核心功能完整的 Promise 出发,深入剖析其实现逻辑。

Promise 核心特性与状态机

一个符合 Promise/A+ 规范的实现必须满足以下几点:

  • Promise 有三种状态:pending(等待)、fulfilled(成功)、rejected(失败)
  • 状态只能由 pending 转为 fulfilled 或 rejected,且一旦确定不可逆
  • 通过 then 方法注册成功和失败的回调,支持链式调用
  • then 的回调函数是异步执行的(微任务)

我们基于这些规则来实现一个简化版的 MyPromise。

基础结构与状态管理

先定义构造函数和基本状态:

function MyPromise(executor) {
  this.state = 'pending';
  this.value = undefined;
  this.reason = undefined;
  this.onFulfilledCallbacks = [];
  this.onRejectedCallbacks = [];

  const resolve = (value) => {
    if (this.state === 'pending') {
      this.state = 'fulfilled';
      this.value = value;
      this.onFulfilledCallbacks.forEach(fn => fn());
    }
  };

  const reject = (reason) => {
    if (this.state === 'pending') {
      this.state = 'rejected';
      this.reason = reason;
      this.onRejectedCallbacks.forEach(fn => fn());
    }
  };

  try {
    executor(resolve, reject);
  } catch (err) {
    reject(err);
  }
}

这里通过数组缓存未执行的回调,确保在异步 resolve/reject 后仍能正确触发。

实现 then 方法

then 方法是 Promise 的核心,需返回一个新的 Promise 以支持链式调用:

BrandCrowd BrandCrowd

一个在线Logo免费设计生成器

BrandCrowd 200 查看详情 BrandCrowd
MyPromise.prototype.then = function(onFulfilled, onRejected) {
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
  onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };

  const promise2 = new MyPromise((resolve, reject) => {
    if (this.state === 'fulfilled') {
      queueMicrotask(() => {
        try {
          const x = onFulfilled(this.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
    }

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

    if (this.state === '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;
};

注意使用 queueMicrotask 模拟微任务执行,保证回调异步且优先于 setTimeout。

处理返回值与链式传递

Promise 链的关键在于 resolvePromise 函数,它决定如何处理 then 回调的返回值:

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

  let called;
  if (x != null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      const then = x.then;
      if (typeof then === 'function') {
        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);
  }
}

这段逻辑判断返回值是否为 Promise,如果是则递归解析,否则直接 resolve。

基本上就这些。虽然省略了 catch、finally、all、race 等方法,但核心机制已完整。手写一遍能真正理解 Promise 如何解决回调地狱、实现链式调用和错误冒泡。不复杂但容易忽略细节,比如循环引用、多次调用保护、异步调度等。

以上就是手写Promise核心原理及源码实现_j*ascript技巧的详细内容,更多请关注其它相关文章!


# 有何不同  # 商机网站建设策划书  # 云龙区品质网站推广前景  # 南京推广运营商招聘网站  # 移动网站建设详细报价表  # 百度关键词排名销售  # 厦门营销推广思路沟通  # 胶州网站建设是什么  # 吉林国外网站推广怎么做  # 订阅号怎么营销推广  # 预约福州seo咨询平台  # 单元测试  # javascript  # 端到  # 如何实现  # 如何用  # 命令行  # 返回值  # 递归  # 链式  # 回调  # ai  # 回调函数  # java 


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


相关推荐: 理解Python模块与全局变量的作用域管理  《明末:渊虚之羽》设计师谈设计角色:那会刚毕业 充满激情  在Runstone环境中高效处理TasteDive API的JSON数据  夸克浏览器网页版最新地址 夸克浏览器官方入口合集  ArchiveofOurOwn小说阅读-ArchiveofOurOwn同人作品访问链接  126邮箱网页版官方入口 126邮箱账号在线登录平台  冬*霸灯泡不亮怎么办_浴霸取暖灯一盏不亮的灯座清洁修复法  Composer的 "check-platform-reqs" 命令有什么用_在部署前检查生产环境是否满足Composer依赖需求  必由学官方网站入口 必由学学生教师共用登录通道  整合Supabase认证与Django模型:跨模式迁移的解决方案  如何在网页中实现特定地点的随机图片展示  如何使用J*aScript精确选择并批量修改特定父元素下子链接的样式  抖音DOU+怎么投最有效 抖音付费推广的ROI提升技巧  在Typer应用中优雅地处理和重组任意命令行参数  在VS Code中配置和运行Dart程序的完整步骤  在J*a中如何隐藏复杂性_使用门面模式组织对象交互  小红书商家版怎样在笔记嵌入商品卡路径_小红书商家版在笔记嵌入商品卡路径【挂载教程】  12306选座怎么选到临时改签座_12306改签选座策略与步骤  谷歌浏览器无痕模式怎么开 Chrome开启无痕浏览设置方法【教程】  星露谷物语官网入口 星露谷物语游戏官网入口  CSS响应式网页如何实现主次模块比例自适应_flex-grow与flex-shrink调整  Node.js 中使用 node-cron 实现定时 API 数据抓取与处理  大麦的“候补”是什么意思 大麦候补购票规则【详解】  qq邮箱日历功能怎么用_创建日程与会议邀请的技巧  html怎么在cmd下运行php文件_cmd运行html中php文件方法【教程】  如何在离线环境中使用Composer_Composer离线安装依赖包的技巧与策略  C++如何实现一个装饰器模式_C++设计模式之动态地给对象添加额外职责  响应式图片在网页设计中的正确实现方法  小米Civi 4录制视频过暗_小米Civi 4亮度优化  解决Rails应用中内容错位与Turbo警告:meta标签误用导致富文本渲染异常  css滚动动画效果怎么实现_使用Animate.css滚动触发动画类  深入理解rpy2中的类型转换:优化Python对象到R矩阵的映射  DLsite中文平台入口 DLsite官网内容在线查看  漫蛙manwa2最新登录网址_漫蛙manwa2手机网页版入口  京东单号查询入口_京东快递订单追踪入口  如何在 Windows 11 中启动游戏手柄设置  J*aScript map 迭代中检测空数组元素的有效方法  SteamMachine定价或为699美元 大家想入手吗?  CKEditor 5 自定义构建在React应用中渲染失败的调试与解决  age动漫网站入口 age动漫官网直接访问入口  AO3最新官网入口公告_2025AO3镜像站实时查询方法  机构:以往存储涨价周期小米利润率实际上有所改善 能转嫁给消费者等  蛙漫移动版在线看 蛙漫手机浏览器直达入口  J*a最大堆Heapify方法修复:索引计算与边界条件深度解析  Fabric Mod开发:在1.19.3+版本中正确添加自定义物品并管理物品组  CSS布局:解决全屏元素100%尺寸与外边距导致的页面溢出问题  c++ dfs和bfs代码 c++深度广度优先搜索算法  在命令行怎么运行html项目_命令行运行html项目方法【教程】  Composer的 "licenses" 命令如何帮助你遵守开源协议_检查项目依赖的许可证合规性  c++中为什么推荐使用using替代typedef_c++现代化类型别名 

搜索