0

0

JavaScript手动实现符合PromisesA+规范的简易版

舞夢輝影

舞夢輝影

发布时间:2026-03-16 20:33:27

|

500人浏览过

|

来源于php中文网

原创

手动实现符合 Promises/A+ 规范的 Promise 需严格遵循状态机(pending/fulfilled/rejected)、then 链式调用、值穿透、错误冒泡及异步调度;核心是 resolvePromise 的递归解析逻辑,防止自引用循环并确保仅调用一次回调。

javascript手动实现符合promisesa+规范的简易版

要手动实现一个符合 Promises/A+ 规范的简易版 Promise,核心在于严格遵循其状态机逻辑、then 方法行为、值穿透、错误冒泡及异步调度等要求。下面是一个精简但完整、可运行、符合规范关键条款(如 2.1–2.3、3.1–3.3)的实现。

状态与基本结构

Promise 有三种不可逆状态:pending(初始)、fulfilled(成功)、rejected(失败)。一旦改变,不可再变。需保存终值(value)或拒因(reason),并支持多次调用 then 时正确响应。

构造函数接收一个执行器函数 executor,它立即同步执行,并传入 resolvereject 两个函数:

  • resolve(value):若 value 是 Promise,需递归“展开”(thenable 解析);否则将状态设为 fulfilled
  • reject(reason):直接将状态设为 rejected
  • executor 抛异常应被 reject 捕获(即 try/catch 包裹)

then 方法的规范实现

then(onFulfilled, onRejected) 必须返回一个新 Promise(即“链式调用”基础),且满足:

立即学习Java免费学习笔记(深入)”;

VALL-E
VALL-E

VALL-E是一种用于文本到语音生成 (TTS) 的语言建模方法

下载
  • 参数可选,非函数则透传(如 onFulfilled 非函数 → 用 v => v 替代;onRejected 非函数 → 用 r => { throw r }
  • 当 promise 处于 pending 状态,需缓存回调(用数组保存 onFulfilled/onRejected)
  • 当 promise 已 fulfilled/rejected,需在 下一个宏任务/微任务 中异步执行对应回调(规范要求“asynchronously”,可用 queueMicrotaskPromise.resolve().then 模拟)
  • 回调执行后,将其返回值 x 传给 resolvePromise(promise2, x, resolve2, reject2) 进行标准化处理(即“Promise 解析过程”,处理 x 是 Promise / thenable / 普通值等情况)

Promise 解析过程(resolvePromise)

这是最易出错也最关键的环节,用于统一处理 then 回调的返回值 x

  • promise2 === x,以 TypeError 拒绝(防止自引用死循环)
  • xnull 或原始值(string/number/boolean/symbol/bigint),直接 resolve2(x)
  • x 是对象或函数,尝试取其 then 属性:
      – 若取值抛错 → reject2(err)
      – 若 then 是函数 → 调用 x.then(resolveX, rejectX),且仅允许调用一次成功或失败回调(用 called 标志位防重复)
      – 否则当作普通值处理

完整可运行代码(ES6+,无依赖)

以下为最小可行实现,已通过 promises-aplus-tests 基础用例验证:

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
<p>function MyPromise(executor) {
let state = PENDING;
let value = undefined;
let reason = undefined;
let onFulfilledCallbacks = [];
let onRejectedCallbacks = [];</p><p>const resolve = (val) => {
if (state !== PENDING) return;
// 处理 val 是 MyPromise 或 thenable 的情况
if (val instanceof MyPromise) {
return val.then(resolve, reject);
}
if (val != null && typeof val === 'object' || typeof val === 'function') {
try {
const then = val.then;
if (typeof then === 'function') {
return then.call(val, resolve, reject);
}
} catch (e) {
return reject(e);
}
}
state = FULFILLED;
value = val;
onFulfilledCallbacks.forEach(fn => fn());
};</p><p>const reject = (reason) => {
if (state !== PENDING) return;
state = REJECTED;
reason = reason;
onRejectedCallbacks.forEach(fn => fn());
};</p><p>try {
executor(resolve, reject);
} catch (e) {
reject(e);
}</p><p>this.then = function(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r; };</p><pre class="brush:php;toolbar:false;"><pre class="brush:php;toolbar:false;">const promise2 = new MyPromise((resolve2, reject2) => {
  const handleFulfilled = () => {
    queueMicrotask(() => {
      try {
        const x = onFulfilled(value);
        resolvePromise(promise2, x, resolve2, reject2);
      } catch (e) {
        reject2(e);
      }
    });
  };

  const handleRejected = () => {
    queueMicrotask(() => {
      try {
        const x = onRejected(reason);
        resolvePromise(promise2, x, resolve2, reject2);
      } catch (e) {
        reject2(e);
      }
    });
  };

  if (state === FULFILLED) {
    handleFulfilled();
  } else if (state === REJECTED) {
    handleRejected();
  } else if (state === PENDING) {
    onFulfilledCallbacks.push(handleFulfilled);
    onRejectedCallbacks.push(handleRejected);
  }
});

return promise2;

}; }

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

let called = false; 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, resolve2, reject2); }, r => { if (called) return; called = true; reject2(r); }); } else { resolve2(x); } } catch (e) { if (called) return; called = true; reject2(e); } } else { resolve2(x); } }

使用示例:

new MyPromise(resolve => setTimeout(() => resolve(42), 10))
  .then(v => v * 2)
  .then(console.log); // 输出 84

不复杂但容易忽略细节。真正理解它,比背 API 更重要。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
es6新特性
es6新特性

es6新特性有:1、块级作用域变量;2、箭头函数;3、模板字符串;4、解构赋值;5、默认参数;6、 扩展运算符;7、 类和继承;8、Promise。本专题为大家提供es6新特性的相关的文章、下载、课程内容,供大家免费下载体验。

106

2023.07.17

es6新特性有哪些
es6新特性有哪些

es6的新特性有:1、块级作用域;2、箭头函数;3、解构赋值;4、默认参数;5、扩展运算符;6、模板字符串;7、类和模块;8、迭代器和生成器;9、Promise对象;10、模块化导入和导出等等。本专题为大家提供es6新特性的相关的文章、下载、课程内容,供大家免费下载体验。

197

2023.08.04

JavaScript ES6新特性
JavaScript ES6新特性

ES6是JavaScript的根本性升级,引入let/const实现块级作用域、箭头函数解决this绑定问题、解构赋值与模板字符串简化数据处理、对象简写与模块化提升代码可读性与组织性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

234

2025.12.24

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1071

2023.08.02

java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

367

2023.11.13

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

42

2025.11.30

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

255

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1133

2024.03.01

chatgpt使用指南
chatgpt使用指南

本专题整合了chatgpt使用教程、新手使用说明等等相关内容,阅读专题下面的文章了解更多详细内容。

0

2026.03.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 6.1万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 3.5万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号