你真的知道 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.
翻译一下:
- HostMakeJobCallback(thenAction) 创建了一个回调函数 thenJobCallback,该函数将在 Promise 的解决程序(resolve)被调用后执行。
- HostMakeJobCallback 意思是宿主环境创建一个回调函数任务(依赖于宿主环境的实现,是抽象的),这个函数
- thenJobCallback 可以理解为 promise 的实例
- 所以简单来说就是 宿主环境在 resolve 之后,把 之前的 resolve(Promise.resolve(2)) 里的 Promise.resolve(2) 在 resolve 调用后执行
- NewPromiseResolveThenableJob(promise, resolution, thenJobCallback) 创建了一个新的 Promise 解决函数任务(Promise Resolve Thenable Job)。这个任务用于将一个 thenable 对象(即具有 .then 方法的对象)转换为 Promise 的解决值。
- 简单理解就是因为 resolve(Promise.resolve(2)) 里面调用的值是 thenable 对象,所以返回的就是这个 thenable 对象
- HostEnqueuePromiseJob(job.[[Job]], job.[[Realm]]) 将上一步创建的 Promise 解决函数任务加入宿主环境的任务队列中,以待执行。这个任务将在宏任务执行时被调用。
- HostEnqueuePromiseJob 是一个宿主环境(host environment)提供的函数,用于将 Promise 相关的任务(Promise Jobs)加入任务队列中以便执行。
- 所以 Promise.resolve(2) 会被放入到微任务队列里面等待执行
好了,结案了,关键语句就是 Promise.resolve(2) 会被放入到微任务队列里面等待执行,所以它还没被执行呢,所以是 pending 状态,又因为 宏任务 执行完毕后,会取出当前微任务队列中所有的微任务执行,所以我们的Promise 又变为了完成态
这是我 Node.js 系列文章的第三篇,也是探索 Javascript 异步任务管理的第一篇,欢迎点赞,收藏。其实可以出一个 Javascript 核心概念的小册,不知道大家有兴趣没?
对了,很多人关心我的 react 组件库,我还在迭代,这个组件库已经用在我们的项目里了,应该算是全网个人 react 组件库做的最好的了吧,其它的 react 组件库教程我至今没看到能上的了生产环境的,谨防被骗哦!