新闻中心
手写Promise核心原理及源码实现_j*ascript技巧
Promise 有 pending、fulfilled、rejected 三种状态,状态一旦改变不可逆;2. 通过 then 方法注册回调并返回新 Promise 实现链式调用;3. 回调异步执行,使用 queueMicrotask 模拟微任务;4. resolvePromise 函数处理 then 返回值,若为 Promise 则递归解析,否则直接 resolve;5. 需防止循环引用和多次调用,确保错误冒泡。

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
一个在线Logo免费设计生成器
200
查看详情
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++现代化类型别名


2025-11-07
浏览次数:次
返回列表
) {
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;
};