你很可能对 Promise 用法一无所知,不信你来看看这个问题你能解释为什么吗?

你真的知道 promise 是如何运行的吗?

在提出问题之前,我们需要一些基本的知识储备,先看看 promise 的几种状态转换:

new Promise的时候,Promise 的初始状态是 pending ,然后内部会有一个叫做 executor 执行函数自动调用,q其执行的成功和失败会让 Promise 的 state, 也就是状态发生变化,state 要么会变为 "fulfilled",完成态(当 resolve 调用的时候) ,要么变为 "rejected",失败状态(reject 调用的时候)。

然后 Promise.resolve() 返回一个 resolved 后的Promise. 如果给 resolve 传入的是一个 promise ,那么返回 promise,否则返回一个 fulfilled 状态 的promise。

根据上面的定义,我们可以得到如下结论:

javascript 复制代码
Promise.resolve(5) -> returns promise<fulfilled>(5) 
Promise.resolve(Promise.resolve(5)) -> returns promise<fulfilled>(5)
  • Promise.resolve(5) -> 返回 fulfilled 状态的 promise
  • Promise.resolve(Promise.resolve(5)) -> 返回 fulfilled 状态的 promise

好了,奇怪的事情马上就要发生了

javascript 复制代码
const promise = new Promise(function(resolve, reject) {
   resolve(5);
});
console.log(promise);

上面你猜返回什么,没错,是 fulfilled 状态的 promise

那下面返回什么呢?

javascript 复制代码
const promise = new Promise(function(resolve, reject) {
   resolve(Promise.resolve(5));
});

console.log(promise);

你是不是同样认为是 fulfilled 状态的 promise 呢? 对不起,错了哦,是 pending 状态的 promise。

但是,如果我们把上面的 promise 如下调用呢?

javascript 复制代码
setTimeout(() => console.log(promise), 0)

这样的 promise 返回的是 fulfilled 状态的 promise。

我了个去,这是咋回事,有点懵逼了啊!

最后问题是:Promise.resolve() 和 new Promise((resolve) => { resolve() } ) 是一样的吗?

我们先来看这个问题

  • Promise.resolve(2) 返回的 promise 是 "fulfilled" 状态,即完成态
  • Promise.resolve(Promise.resolve(2)) 返回的 promise 也是 "fulfilled" 状态
  • new Promise((resolve) => { resolve(2) } ) 返回的 promise 也是 "fulfilled" 状态

奇怪事情来了

javascript 复制代码
const promise = new Promise((resolve) => { 
  resolve(Promise.resolve(2));
});
console.log(promise);

返回的 promise 是什么状态呢?

居然是 pending 态,这就疑了惑了啊!

为什么是这样呢?

我们不得不去ecmascript 262的文档里面寻求答案,执行 promise 有很多过程,最终我们关心的是影响我们刚才结果的规则到底在哪,全部规则网址如下,有兴趣的同学自己可以去探索,我们聚焦到第13 - 15 条规则

javascript 复制代码
13. Let thenJobCallback be HostMakeJobCallback(thenAction).
14. Let job be NewPromiseResolveThenableJob(promise, resolution, thenJobCallback).
15. Perform HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]).
16. Return undefined.

翻译一下:

  1. HostMakeJobCallback(thenAction) 创建了一个回调函数 thenJobCallback,该函数将在 Promise 的解决程序(resolve)被调用后执行。
    1. HostMakeJobCallback 意思是宿主环境创建一个回调函数任务(依赖于宿主环境的实现,是抽象的),这个函数
    2. thenJobCallback 可以理解为 promise 的实例
    3. 所以简单来说就是 宿主环境在 resolve 之后,把 之前的 resolve(Promise.resolve(2)) 里的 Promise.resolve(2) 在 resolve 调用后执行
  2. NewPromiseResolveThenableJob(promise, resolution, thenJobCallback) 创建了一个新的 Promise 解决函数任务(Promise Resolve Thenable Job)。这个任务用于将一个 thenable 对象(即具有 .then 方法的对象)转换为 Promise 的解决值。
    1. 简单理解就是因为 resolve(Promise.resolve(2)) 里面调用的值是 thenable 对象,所以返回的就是这个 thenable 对象
  3. HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]) 将上一步创建的 Promise 解决函数任务加入宿主环境的任务队列中,以待执行。这个任务将在宏任务执行时被调用。
    1. HostEnqueuePromiseJob 是一个宿主环境(host environment)提供的函数,用于将 Promise 相关的任务(Promise Jobs)加入任务队列中以便执行。
    2. 所以 Promise.resolve(2) 会被放入到微任务队列里面等待执行

好了,结案了,关键语句就是 Promise.resolve(2) 会被放入到微任务队列里面等待执行,所以它还没被执行呢,所以是 pending 状态,又因为 宏任务 执行完毕后,会取出当前微任务队列中所有的微任务执行,所以我们的Promise 又变为了完成态

这是我 Node.js 系列文章的第三篇,也是探索 Javascript 异步任务管理的第一篇,欢迎点赞,收藏。其实可以出一个 Javascript 核心概念的小册,不知道大家有兴趣没?

对了,很多人关心我的 react 组件库,我还在迭代,这个组件库已经用在我们的项目里了,应该算是全网个人 react 组件库做的最好的了吧,其它的 react 组件库教程我至今没看到能上的了生产环境的,谨防被骗哦!

相关推荐
北北~Simple6 分钟前
第一次搭建数据库
服务器·前端·javascript·数据库
GanGuaGua12 分钟前
Vue3常用指令
前端·javascript·vue.js
欧阳天风12 分钟前
录音实时上传
前端·javascript
江号软件分享17 分钟前
从DNS到防火墙:NetDisabler多策略断网方法详解
前端
灵犀学长25 分钟前
解锁HTML5页面生命周期API:前端开发的新视角
前端·html·html5
江号软件分享34 分钟前
轻松解决Office版本冲突问题:卸载是关键
前端
致博软件F2BPM41 分钟前
Element Plus和Ant Design Vue深度对比分析与选型指南
前端·javascript·vue.js
慧一居士2 小时前
flex 布局完整功能介绍和示例演示
前端
DoraBigHead2 小时前
小哆啦解题记——两数失踪事件
前端·算法·面试
一斤代码7 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue