如何理解Promise中,运行 [[Resolve]](promise, x),所呈现的异步特性
[[Resolve]](promise, x)如果 x 为 Promise ,则使 promise 接受 x 的状态 注4:
如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
如果 x 处于执行态,用相同的值执行 promise
如果 x 处于拒绝态,用相同的据因拒绝 promise
如果 x 不为对象或者函数,以 x 为参数执行 promise
以上摘录自Promise/A+规范
如果按照规范中的描述,那么当x=10 或者 x = Promise.resolve(10)时,两者的表现应该是相同的。他会拿出这个为执行态的promise的值,进行一次resolve。这整个过程应该类似于语法糖?但事实好像有点偏差
我们来看一段代码
new Promise((resolve, reject) => {
let a = new Promise(resolve => {
resolve(10)
})
let b = new Promise(resolve => {
let c = Promise.resolve(10)
resolve(c)
})
console.log(a)
console.log(b)
Promise.resolve(0)
.then(() => {
console.log('micro1')
console.log(b)
})
.then(() => {
console.log('micro2')
console.log(b)
})
setTimeout(() => {
console.log('marco')
console.log(b)
})
})
这是输出
Promise { 10 }
Promise { <pending> }
micro1
Promise { <pending> }
micro2
Promise { 10 }
marco
Promise { 10 }
我们可以看到,当[[Resolve]](promise, x)
时,如果X是一个普通值,将会立即同步的更改此Promise状态为执行态Fulfilled
.
但是当X是一个状态为执行态的Promise对象时,promise对象的状态没有被立即改变,改变的时间点也非常的奇怪,如果这个我称为状态同步
的过程是一个异步的放置在microTask中的任务,那么他应该改变在micro1之前(因为他会被更早的插入microTask之中)。如果他放置到marcoTask,那么他应该发生在运行setTimeout之前。
所以我的问题其实就是如何理解这个过程。
- 这个
状态同步
会放置到microTask中吗 - 如果是,它何时被放到microTask之中
- 有相关的规范描述这个过程吗
在提出问题的同时,我自己也在积极找寻答案,以下放最新进展
进展
- Chrome中实现的应该是ES6 Promise规范,并非Promise/A+规范。ES6 Promise来源于Promise/A+规范。
- 以上这个状态同步似乎有官方称呼PromiseResolveThenableJob,这个过程并不会放到microTask中,他会放到名为
PromiseJobs
的 job queue中。 - 好吧,job queue是microTask的别名,这玩意就是放到microTask中执行的。
猜想
根据以上的一些信息,我个人产生了这样的猜想
PromiseResolveThenableJob 分为两步,第一步,首先放一个任务A进microTask中,A的操作是检查目标X的状态,如果状态为执行态,那么继续放入一个任务B到microTask中,B的内容才是语法糖resolve(x的值),如此分为两步添加。能够解释上面的奇怪顺序问题。exp:同步代码运行后microTask中有任务A和Micro1 接下来执行任务A,放置任务B到microTask队尾,执行Micro1,接下来执行任务B,更改Promise状态。
以上还没有详细的规范支撑,只是一个猜想
追问
那这样是不是可以认为
let b = new Promise(resolve => {
let c = Promise.resolve(10)
resolve(c)
})
可以认为是如下的语法糖
let b = new Promise(resolve => {
Promise.resolve(10).then(res => {
resolve(res)
})
})
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
你可能被
console.log
误导了。虽然打印显示 Promise 已经 fulfill 了,但其onFulfilled
必然会在平台代码执行完了才会开始的(见规范底部注解)。所以
b
里的resolve(c)
会在第二轮清理 Promise 队列时才会被处理。而第二轮中新增的
micro1
会加到栈前新的队列,所以会先于b
被 fulfilled 。micro2
已经到第三轮了,这时b
已经被 fulfilled。最后帮你列出整个方便理解。
第一次平台代码执行后栈中添加了一条队列
清理栈,新增的 Promises 被添加到栈上新的队列
第二轮清理
第三轮