新闻中心
手写一个符合Promises/A+规范的Promise_j*ascript技巧
实现一个符合 Promises/A+ 规范的 Promise 需遵循状态不可变、异步执行、链式调用等规则,核心包括三种状态(pending、fulfilled、rejected)、then 方法返回新 Promise、resolvePromise 处理返回值、catch 和 finally 的语法糖实现,以及静态 resolve 和 reject 方法,完整覆盖规范关键机制。

实现一个符合 Promises/A+ 规范的 Promise 并不只是写个简单的异步容器,而是要严格遵循状态机制、异步解析和链式调用等核心规则。下面是一个精简但完全符合 Promises/A+ 规范核心
逻辑的手写 Promise 实现,包含关键特性:状态管理、then 链式调用、值穿透、错误捕获以及异步执行。
Promise 的三种状态
Promise 有三个状态:
- pending:初始状态,未完成也未拒绝
- fulfilled:操作成功完成
- rejected:操作失败
状态一旦从 pending 变为 fulfilled 或 rejected,就不能再改变。
基本结构与状态控制
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 (error) {
reject(error);
}
}
构造函数接收一个执行器函数(executor),立即执行,并传入 resolve 和 reject 函数。通过闭包维护状态和回调队列。
实现 then 方法
then 方法是 Promise 的核心,必须返回一个新的 Promise,以支持链式调用。
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') {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.state === 'pending') {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
return promise2;
};
注意使用 setTimeout 模拟异步微任务(实际规范中应使用 queueMicrotask,但 setTimeout 在浏览器中可模拟异步行为)。
万相营造
阿里妈妈推出的AI电商营销工具
168
查看详情
处理返回值 resolvePromise
这个函数决定如何处理 then 回调的返回值 x,是 Promises/A+ 最复杂的一部分。
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
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, 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);
}
}
该函数判断 x 是否为 Promise 或类 Promise 对象(有 then 方法),递归解析直到得到最终值。
补充方法:catch 和 finally
catch 是 then 的语法糖,只处理错误。
MyPromise.prototype.catch = function(onRejected) {
return this.then(null, onRejected);
};
MyPromise.prototype.finally = function(callback) {
return this.then(
value => MyPromise.resolve(callback()).then(() => value),
reason => MyPromise.resolve(callback()).then(() => { throw reason; })
);
};
finally 不影响结果值,无论成功或失败都会执行 callback。
静态方法:resolve 和 reject
MyPromise.resolve = function(value) {
return new MyPromise(resolve => resolve(value));
};
MyPromise.reject = function(reason) {
return new MyPromise((_, reject) => reject(reason));
};
基本上就这些。这个手写 Promise 覆盖了 Promises/A+ 的主要规范点:状态不可逆、then 返回新 Promise、异步执行、错误捕获、链式解析。虽然没有覆盖所有边界测试,但已足够理解其核心机制。在真实项目中推荐使用原生 Promise,但在面试或学习时,这种实现能深刻掌握异步编程原理。
以上就是手写一个符合Promises/A+规范的Promise_j*ascript技巧的详细内容,更多请关注php中文网其它相关文章!
# java
# 荣成可信网站建设
# 网站建设企业采购
# 搜狗流量seo案例
# 网店营销和推广推广方案
# 邢台专业网站建设工作
# 但在
# 就不
# 是一个
# 不匹配
# 中不
# 回调
# 三种
# 返回值
# 递归
# 链式
# ai
# 浏览器
# javascript
# 编程
# php
# 贵州seo优化公司平台
# 网站优化南通
# 东莞仓储seo软件有哪些
# seo要懂建站那些
# 营销推广策略定义
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
AWS EC2实例间SQL Server连接超时:安全组配置与故障排除指南
纯CSS与HTML网格布局的HTML精简策略:SVG与JS方案解析
UC浏览器如何安装插件 UC浏览器添加扩展程序详细教程【进阶】
PHP中获取MongoDB服务器运行时间(Uptime)的专业指南
Win11怎么设置开机NumLock亮 Win11修改注册表InitialKeyboardIndicators值
CSS实现侧边栏导航项全宽圆角悬停背景效果
邮政快递包裹最新位置 邮政快递实时追踪入口
126邮箱账号注册 电脑版登录入口
Discord Slash 命令响应超时问题的异步解决方案
零跑汽车11月交付量达70327台 实现连续9个月正增长
必由学登录入口 必由学官方网站在线访问链接
Yandex搜索引擎官网入口_俄罗斯Yandex免登录一键直达
顺丰快递查询系统 官方正版查询入口
谷歌浏览器无痕模式怎么开 Chrome开启无痕浏览设置方法【教程】
今日头条怎么同步内容到抖音_今日头条内容同步到抖音教程
vivo云服务网页版登录 怎么登录vivo云服务网页版
优化LangChain文档加载与ChromaDB集成:解决多文档处理与分块问题
极兔快递快件信息查询系统 极兔快递官网运单号追踪
没有大陆身份证/银行卡如何实名微信? 亲测有效的几种方法分享
CSS布局中意外空白:解决padding-top导致的顶部间距问题
中兴BladeV30怎样用测距估书架层高_iPhone中兴BladeV30测距估书架层高【家装参考】
多闪网页版在线观看免费入口_多闪官网访问入口
Python字典中优雅地迭代剩余元素的方法
CKEditor 5 自定义构建在React应用中渲染失败的调试与解决
2026年发布! 美少女养成动作RPG《神剑少女战记》发布实机演示
俄罗斯搜索引擎Yandex指南 附2025年免登录官网入口
Golang如何优化CPU绑定任务分配策略_Golang CPU任务分配优化实践
QQ邮箱登录平台入口 QQ邮箱网页版邮箱官方入口
Lar*el头像管理:图片缩放与旧文件删除的最佳实践
拼多多赚钱渠道_拼多多收益来源
Python getattr() 异常处理深度解析:避免程序意外退出
邮政编码查询不到怎么办_邮政编码查询不到的常见原因与对策
顺丰快递查单号物流信息 顺丰快递小程序查询入口
利用Bokeh CustomJS动态控制DataTable列可见性
QQ邮箱稳定登录入口_QQ邮箱官方网站网页版使用
双系统安装时,如何设置默认启动系统? msconfig命令了解一下!
格力空气能E5故障代码是什么情况_格力空气能E5代码解析与应对措施
优化Django表单:提交验证失败后保留用户输入
qq游戏大厅官方下载_qq游戏免费下载安装入口
Composer中的^和~符号代表什么_精通Composer版本号语义化约束
TikTok国际版官网直达_TikTok国际版官网直达进入在线观看
快速CSGO开箱网站指南 CSGO开箱平台推荐
为什么简单的XML文件也会解析失败? 检查隐藏的非打印字符(如BOM)的方法
TikTok网页版直接登录 TikTok网页端官方平台入口
Node.js中HTML按钮与J*aScript函数交互的正确姿势
最新韩小圈网页版登录入口_官网在线观看官方链接
C++如何检测键盘输入_C++ _kbhit与_getch函数非阻塞输入
生成rdflib自定义SPARQL函数:参数匹配与实践指南
夸克AO3官网入口_AO3镜像网站2025推荐
Golang如何安装Swagger工具_GoSwagger文档生成环境


2025-10-31
浏览次数:次
返回列表