新闻中心
手写一个符合Promises/A+规范的Promise_js深度探索
答案:手写符合Promises/A+规范的Promise需实现状态机、then链式调用与resolvePromise递归解析;包含pending/fulfilled/rejected三种状态,通过resolve/reject函数改变状态,then方法返回新Promise并注册回调,利用queueMicrotask确保异步执行,resolvePromise处理返回值为Promise或thenable的情况,防止循环引用,同时实现catch、finally、resolve、reject等辅助方法。

要手写一个符合 Promises/A+ 规范的 Promise,关键在于理解其核心机制:状态机、异步执行、then 方法的链式调用与穿透,以及 onFulfilled 和 onRejected 的回调调度。下面从零实现一个精简但完全符合规范的 Promise 类。
Promise 核心状态与基本结构
Promise
有三种状态:pending(等待)、fulfilled(成功)、rejected(失败)。一旦状态变更,就不能再改变。
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = '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);
}
}
实现 then 方法
then 方法是 Promise 的核心,必须返回一个新的 Promise,实现链式调用。它接收两个可选参数:onFulfilled 和 onRejected。
MyPromise.prototype.then = function(onFulfilled, onRejected) {
// 处理透传,支持 .then().then(value => ...)
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };
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;
};
处理 then 返回值:resolvePromise 函数
这个函数决定如何处理 onFulfilled/onRejected 的返回值 x。根据 Promises/A+ 规范,x 可能是普通值、Promise 或带有 then 方法的对象(即“thenable”)。
BrandCrowd
一个在线Logo免费设计生成器
200
查看详情
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called = false;
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
let then;
try {
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);
}
}
补充常用方法:catch、finally、resolve、reject
这些是基于 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; })
);
};
MyPromise.resolve = function(value) {
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value));
};
MyPromise.reject = function(reason) {
return new MyPromise((_, reject) => reject(reason));
};
基本上就这些。这个实现覆盖了 Promises/A+ 的主要测试用例,包括异步回调、链式调用、错误捕获、循环引用检测等。关键是理解 resolvePromise 如何递归解析 thenable,以及 queueMicrotask 确保回调异步执行,模拟原生 microtask 队列行为。
以上就是手写一个符合Promises/A+规范的Promise_js深度探索的详细内容,更多请关注其它相关文章!
# 就不
# seo优化稿件网站
# 电影怎么做营销推广的呢
# 信阳网站网络推广团队
# 车辆seo怎么关掉
# 上海搜索优化seo
# 网络营销策划推广的方法
# 网站 线下推广
# s公司网站建设价格
# 营销推广服务的税收分类
# 网站优化技术分析报告
# js
# 加载
# 返回值
# 按需
# 服务端
# 如何用
# 如何使用
# 回调
# 递归
# 链式
# ai
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
qq浏览器打开空白页怎么办 qq浏览器启动后显示白屏的解决教程
Linux如何排查内存不足OOME问题_LinuxOOM分析教程
深入理解Go语言中的指针类型:以*string为例
Excel函数批量查找替换超快方法_Excel用REPLACE和FIND函数秒级替换
蛙漫官网漫画入口地址_蛙漫在线畅读无广告弹窗
Golang如何优化内存分配与垃圾回收_Golang内存管理与GC优化实践
win11如何加载ICC颜色配置文件 Win11校色文件安装与显示器色彩管理【指南】
J*aScript中正确使用querySelectorAll与复杂CSS选择器
晋江读书网页版在线登录 晋江读书电脑版官网
J*aScript中管理异步API调用:确保操作顺序与数据一致性
Python中高效访问嵌套字典与列表中的键值对
Python vgamepad库按键模拟:正确使用XUSB_BUTTON常量
Excel文件在线转换快速入口 Excel在线格式转换网站
地铁跑酷免费秒玩入口链接 地铁跑酷小游戏免费秒玩网站
J*a中实现Go语言select通道多路复用机制
邮政快递包裹最新位置 邮政快递实时追踪入口
现代化 SciPy 一维插值:interp1d 的替代方案与最佳实践
一加 14R 快充无反应_一加 14R 充电优化
Go RPC HTTP服务正确实现与常见陷阱解析
机构:以往存储涨价周期小米利润率实际上有所改善 能转嫁给消费者等
微博网页版官方账号登录 微博网页版内容浏览使用指南
单射、满射与双射的关系 一文理清所有逻辑
必由学官网入口 必由学教师登录入口
处理动态列数据:J*a ArrayList的正确初始化与字符累加教程
漫蛙2在线漫画入口 漫蛙正版漫画网页版直达
J*a最大堆Heapify方法修复:索引计算与边界条件深度解析
凉拌黄瓜怎么拌更入味 凉拌黄瓜简单家常做法
Go与Ruby之间实现AES加密互通:CFB模式下的密钥长度匹配策略
如何将一个大型PHP应用拆分为多个Composer包_微服务与模块化架构的Composer实践
深入理解J*aScript Promise异步执行与微任务队列
Lar*el Form Request中唯一性验证在更新操作中的正确实现
TikTok国际版网页端快速入口 TikTok全球版短视频浏览教程
字由网在线版登录地址 字由网网页版安全入口
Angular响应式表单:实现提交后表单及按钮的禁用与只读化
特斯拉自动驾驶房车计划曝光 原型车将于2027年亮相
夸克浏览器桌面版同步不了书签怎么处理 夸克浏览器跨设备同步异常解决方案
J*aScript数据结构转换:将对象数组按类别分组
sublime如何配置Go语言开发环境_sublime搭建Golang编译运行系统
HTML转PPT成品工具有哪些?HTML网页转PPT成品工具大全
动漫花园资源网使用步骤_动漫花园资源网下载流程
win11开机启动修复循环怎么办 Win11无法进入系统高级启动解决方法【修复】
LINUX下如何进行磁盘分区_fdisk与parted工具在LINUX中的使用对比
解决J*aScript中重复选择项的确认对话框显示问题
为什么我的微信朋友圈看不到别人的更新_微信朋友圈更新显示异常解决方法
c++中的const_cast和reinterpret_cast怎么用_c++四种类型转换
C++的std::forward_list怎么用_C++ STL中单向链表容器的特点与应用
DLsite中文平台入口 DLsite官网内容在线查看
CSS布局:解决全屏元素100%尺寸与外边距导致的页面溢出问题
C++ explicit关键字防止隐式转换_C++构造函数安全规范
NVIDIA股价11月重挫12%:下月有望好转 但难回5万亿美元巅峰


2025-11-05
浏览次数:次
返回列表