Promise Execute
Promise是一个对象,用作延迟(可能还有异步)计算最终结果的占位符。
Note
promise是一个值(且该值在当前状态下并不知道)的代理,当Promise创建的时候。 其允许你关联成功或者失败的操作事件。让异步的操作看起来像是同步的操作(异步方法是不会立即返回最终的值, 而是返回一个Promise, 在未来的某个时刻使用)
任何Promise都处于三种相互排斥的状态之一:fullfilled、rejected和pending:
- 如果p.then(f, r)将立即排队到任务中,立即调用
f
, 则promise对象p的状态是fulfilled - 如果p.then(f, r)将立即排队到任务中,立即调用
r
, 则promise对象p的状态是rejected - 如果p的状态既不是fulfilled也不是rejected,则其状态是pending
Promise Internal value of invoke constructor
当Promise的构造函数被调用时,有以下两件事触发:
- A Promise Object is created
此Promise对象内部有以下插槽:
[[PromiseState]]
[[PromiseResult]]
[[PromiseIsHandled]]
[[PromiseFullfillReactions]]
[[PromiseRejectReactions]]
- A Promise capability record is created
它封装了Promise,并且添加了一些额外的函数来resolve
或者reject
Promise,这些函数控制了Promise最终的
[[PromiseState]]
和[[PromiseResult]]
,并且启动了异步任务。
通过调用resolve
来resolve Promise,可以通过调用executor
函数来获取。
当调用resolve
函数时:
[[PromiseState]]
由pending
设置为fulfilled
[[PromiseResult]]
设置为done
[[PromiseIsHandled]]
设置为false
Promise Internal value of invoke then
当调用then
函数时,[[PromiseFulfillReactions]]
和[[PromiseRejectReactions]]
在其中发挥着作用。
[[PromiseFulfillReactions]]
field包含Promise Reaction,这是一个通过将then
处理程序链接到promise而创建的对象。
Promise Reaction的属性[[Handler]]
指向了then
中的回调函数,当Promise被resolve,此回调函数被加入了
Microtask Queue
,并且可以访问和解析Promise的值。
当Promise resolves时,这个处理回调函数接收[[PromiseResult]]
的值作为其参数,之后它被推送到微任务队列。
Note
微任务队列是一个特殊的队列在事件循环中,当调用栈是空的,事件循环程序中首先会处理为任务队列中的任务,直到微任务队列为空, 然后再处理任务队列(宏任务队列或者回调队列)
同样的,也可以创建Promise Reaction record 来处理Promise rejection,通过catch
,此catch
的参数回调函数也会被
加入微任务队列。
到目前为止,我们只在executor
函数中直接调用了resolve
或reject
。虽然这是可能的,但它并没有充分利用Promise的力量(和主要目的)!
在大多数情况下,我们会想要在某个稍后的时间点resolve
或reject
,通常是在异步任务完成时。
这里我们使用setTimeout
来模拟异步任务。
new Promise((resolve,reject) => {setTimeout(() => {resolve('done')}, 1000);}).then(result => console.log(result))
首先,new Promise
构造函数加入到了调用栈,并且创建了Promise 实例
然后,executor
函数执行了,调用了setTimeout
, 其被加入到了调用栈。
setTimeout
负责调度Timers Web API中的计时器,延迟为1000ms,之后我们传递给setTimeout
的回调将被推送到任务队列。
在计时器和Promise构造函数从调用堆栈中弹出后,引擎会遇到then
。
then
被加入到了调用栈,并且创建了一个Promise Reaction record,其属性[[handler]]
指向了then
的回调函数。
由于[[PromiseState]]
仍是"pending"
,Promise Reaction record被加入到了[[PromiseFulfillReactions]]
列表中。
当1000ms到达时,setTimeout
回调函数被加入到任务队列中。
此时调用栈中如果有其他任务,则执行其他任务,直到此setTimeout
的回调,此时回调会从任务队列中进入到调用栈,立即执行回调。
此时,会执行resolve
,[[PromiseState]]
设置为"fulfilled"
,[[PromiseResult]]
设置为"done"
,此时
跟Promise Reaction record相关联的代码被加入到了微任务队列,然后调用栈弹出了回调函数和resolve
。
由于调用堆栈是空的,事件循环首先检查then
处理程序的回调正在等待的微任务队列。
然后then
回调函数进入调用栈,打印result
的值,也就是Promise内部插槽属性[[PromiseResult]]
的值"done"
。
一旦回调完成执行并从调用堆栈中弹出,程序就完成了!
Promise Internal value of multi then
除了创建Promise reaction record之外,then
也会返回一个Promise,也就意外着可以将多个then
进行链式调用。
new Promise((resolve,reject) => {resolve(1)}).then(result => result * 2).then(result => result * 2).then(result => console.log(result))
当此代码执行时,调用Promise构造函数时会创建一个Promise对象。之后,每当引擎遇到then
时,
都会创建Promise Reaction record和Promise对象。
在这两种情况下,then回调都将接收到的[[PromiseResult]]
值乘以2。then的[[PromiseResult]]
被设置为该计算的结果,
该结果又被下一个then的处理程序使用。
最终,结果被打印出来了。最后一个then promise的[[PromiseResult]]
是undefined
,因为我们没有显式返回值,这意味着它隐式返回了未定义的值。
Conclusion
Promise是一个具有一些额外的功能来改变其内部状态的对象。
而这些额外的功能也就是最酷的事情,如果其被then
或者catch
附加的话,是可以触发异步的操作。
由于这些处理程序被添加到微任务队列中,因此你可以以非阻塞的方式处理这些最终的结果。处理错误也是
容易的。将多个处理程序链接到一起,可以使你的代码具有可读性可可维护性!