你很可能对 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 组件库教程我至今没看到能上的了生产环境的,谨防被骗哦!

相关推荐
Hello-Mr.Wang2 分钟前
vue3中开发引导页的方法
开发语言·前端·javascript
程序员凡尘30 分钟前
完美解决 Array 方法 (map/filter/reduce) 不按预期工作 的正确解决方法,亲测有效!!!
前端·javascript·vue.js
编程零零七4 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql
北岛寒沫5 小时前
JavaScript(JS)学习笔记 1(简单介绍 注释和输入输出语句 变量 数据类型 运算符 流程控制 数组)
javascript·笔记·学习
everyStudy5 小时前
JavaScript如何判断输入的是空格
开发语言·javascript·ecmascript
(⊙o⊙)~哦6 小时前
JavaScript substring() 方法
前端
无心使然云中漫步6 小时前
GIS OGC之WMTS地图服务,通过Capabilities XML描述文档,获取matrixIds,origin,计算resolutions
前端·javascript
Bug缔造者6 小时前
Element-ui el-table 全局表格排序
前端·javascript·vue.js
xnian_7 小时前
解决ruoyi-vue-pro-master框架引入报错,启动报错问题
前端·javascript·vue.js
麒麟而非淇淋8 小时前
AJAX 入门 day1
前端·javascript·ajax