专栏名称: 程序员大咖
程序员大咖,努力成就期待着的自己。分享程序员技术文章、程序员工具资源、程序员精选课程、程序员视频教程、程序员热点资讯、程序员学习资料等。
目录
相关文章推荐
Kevin在纽约  ·  特斯拉股价今天收盘重挫15.4%,报每股22 ... ·  2 天前  
最高人民法院  ·  全国人大代表热议最高法院工作报告(十七) ·  2 天前  
最高人民法院  ·  全国人大代表热议最高法院工作报告(十五) ·  2 天前  
最高人民法院  ·  欢迎来到女法官的世界! ·  3 天前  
51好读  ›  专栏  ›  程序员大咖

JavaScript 可视化:Promise执行彻底搞懂

程序员大咖  · 公众号  ·  · 2025-02-23 10:24

正文

深入探讨了 JavaScript 中 Promise 的内部机制,解释了它们如何使异步任务以非阻塞方式执行,并展示了 Promise 的创建、状态变化以及与事件循环的关系。

正文从这开始~~

JavaScript 中的 Promise 一开始可能会让人感到有些难以理解,但是如果我们能够理解其内部的工作原理,就会发现它们其实是非常易于掌握的。

在这篇博客文章中,我们将深入探讨 Promise 的一些内部机制,并探索它们是如何使得 JavaScript 能够执行非阻塞的异步任务。

一种创建 Promise 的方式是使用 new Promise 构造函数,它接收一个执行函数,该函数带有 resolve 和 reject 参数。

 new Promise((resolve, reject) => {
// TODO(Lydia): Some async stuff here
});

当 Promise 构造函数被调用时,会发生以下几件事情:

  • 创建一个 Promise 对象。这个 Promise 对象包含几个内部槽,包括 [[PromiseState]] [[PromiseResult]] [[PromiseIsHandled]] [[PromiseFulfillReactions]] [[PromiseRejectReactions]]

  • 创建一个 Promise 能力记录。这个记录 “封装” 了 Promise,并增加了额外的功能来 resolve 或 reject promise。这些功能可控制 promise 的最终 [[PromiseState]] [[PromiseResult]] ,并启动异步任务。

我们可以通过调用 resolve 来解决这个 Promise,这是通过执行函数可以实现的。当我们调用 resolve 时:

  • [[PromiseState]] 被设置为 “已实现”(fulfilled)。

  • [[PromiseResult]] 被设置为我们传递给 resolve 的值,在这种情况下是 “完成!”(Done!)。

调用 reject 时的过程类似,现在 [[PromiseState]] 被设置为 “已拒绝”(rejected),并且 [[PromiseResult]] 被设置为我们传递给 reject 的值,这是 “失败!”(Fail!)。

当然很好。但是,使用函数来改变对象内部属性有什么特别的呢?

答案就在与我们目前跳过的两个内部槽相关的行为中: [[PromiseFulfillReactions]] [[PromiseRejectReactions]]

[[PromiseFulfillReactions]] 字段包含 Promise Reactions。这是一个通过将 then 处理程序链接到 Promise 而创建的对象。

此 Promise Reaction 包含一个 [[Handler]] 属性,其中包含我们传递给它的回调。当 promise resolve 时,该处理程序会被添加到微任务队列中,并可访问 promise 解析时的值。

当 promise 解析时,这个处理程序接收到 [[PromiseResult]] 的值作为其参数,然后将其推送到 Microtask Queue 微任务队列。

这就是 promise 的异步部分发挥作用的地方!

微任务队列是事件循环(event loop)中的一个专门队列。当调用栈(Call Stack)为空时,事件循环首先处理微任务队列中等待的任务,然后再处理来自常规任务队列(也称为 “回调队列” 或 “宏任务队列”)的任务。

如果你想了解更多,可以查看我的事件循环视频!

类似地,我们可以通过链式 catch 来创建一个 Promise Reaction 记录来处理 Promise Reject。当 Promise 被拒绝时,这个回调会被添加到微任务队列。

到目前为止,我们只是在执行函数内直接调用 resolve 或 reject。虽然这是可能的,但它并没有充分利用 Promise 的全部功能(和主要目的)!

在大多数情况下,我们希望在稍后的某个时间点(通常是异步任务完成时)进行 resolve 或 reject。

异步任务在主线程之外执行,例如读取文件(如 fs.readFile)、提出网络请求(如 https.get 或 XMLHttpRequest),或者像定时器(setTimeout)这样简单的任务。

当这些任务在未来某个未知的时间点完成时,我们可以使用此类异步操作通常提供的回调功能,要么使用异步任务返回的数据进行 resolve,要么在发生错误时进行 reject。

为了直观地说明这一点,让我们一步步来执行。为了让这个演示简单但仍然真实,我们将使用 setTimeout 来添加一些异步行为。

 new Promise((resolve) => {
setTimeout(() => resolve("Done!"), 100);
}).then(result => console.log(result))

首先,将 new Promise 构造函数添加到调用栈,并创建 Promise 对象。







请到「今天看啥」查看全文