zoukankan      html  css  js  c++  java
  • Promise V8 一源码分析2------------引用

     
            3.2 PerformPromiseThenImpl
    1. transitioning macro PerformPromiseThenImpl(implicit context: Context)(

    2. promise: JSPromise, onFulfilled: Callable|Undefined,

    3. onRejected: Callable|Undefined,

    4. resultPromiseOrCapability: JSPromise|PromiseCapability|Undefined): void {

    5. if (promise.Status() == PromiseState::kPending) {

    6. // penging 状态的分支

    7. // The {promise} is still in "Pending" state, so we just record a new

    8. // PromiseReaction holding both the onFulfilled and onRejected callbacks.

    9. // Once the {promise} is resolved we decide on the concrete handler to

    10. // push onto the microtask queue.

    11. const handlerContext = ExtractHandlerContext(onFulfilled, onRejected);

    12. // 拿到 Promise 的 reactions_or_result 字段

    13. const promiseReactions =

    14. UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result);

    15. // 考虑一个 Promise 可能会有多个 then 的情况,reaction 是个链表

    16. // 存 Promise 的所有处理函数

    17. const reaction = NewPromiseReaction(

    18. handlerContext, promiseReactions, resultPromiseOrCapability,

    19. onFulfilled, onRejected);

    20. // reactions_or_result 可以存 Promise 的处理函数,也可以存

    21. // Promise 的最终结果,因为现在 Promise 处于 pending 状态,

    22. // 所以存的是处理函数 reaction

    23. promise.reactions_or_result = reaction;

    24. } else {

    25. // fulfilled 和 rejected 状态的分支

    26. const reactionsOrResult = promise.reactions_or_result;

    27. let microtask: PromiseReactionJobTask;

    28. let handlerContext: Context;

    29. if (promise.Status() == PromiseState::kFulfilled) {

    30. handlerContext = ExtractHandlerContext(onFulfilled, onRejected);

    31. microtask = NewPromiseFulfillReactionJobTask(

    32. handlerContext, reactionsOrResult, onFulfilled,

    33. resultPromiseOrCapability);

    34. } else

    35. deferred {

    36. assert(promise.Status() == PromiseState::kRejected);

    37. handlerContext = ExtractHandlerContext(onRejected, onFulfilled);

    38. microtask = NewPromiseRejectReactionJobTask(

    39. handlerContext, reactionsOrResult, onRejected,

    40. resultPromiseOrCapability);

    41. if (!promise.HasHandler()) {

    42. runtime::PromiseRevokeReject(promise);

    43. }

    44. }

    45. // 即使调用 then 方法时 promise 已经处于 fulfilled 或 rejected 状态,

    46. // then 方法的 onFulfilled 或 onRejected 参数也不会立刻执行,而是进入

    47. // microtask 队列后执行

    48. EnqueueMicrotask(handlerContext, microtask);

    49. }

    50. promise.SetHasHandler();

    51. }

    3.2.1 PerformPromiseThenImpl 函数的 penging 分支

    PerformPromiseThenImpl 有两个分支,pending 分支调用 NewPromiseReaction 函数,在接收到的 onFulfilled 和 onRejected 参数的基础上,生成 PromiseReaction 对象,存储 Promise 的处理函数,并赋值给 JSPromise 的 reactionsorresult 字段;

    考虑一个 Promise 可以会连续调用多个 then 的情况,比如

    1. const myPromise4 = new Promise((resolve, reject) => {

    2. setTimeout(_ => {

    3. resolve('my code delay 5000')

    4. }, 5e3)

    5. })

    6. myPromise4.then(result => {

    7. console.log('第 1 个 then')

    8. })

    9. myPromise4.then(result => {

    10. console.log('第 2 个 then')

    11. })

    myPromise4 调用了两次 then 方法,每个 then 方法都会生成一个 PromiseReaction 对象。第一次调用 then 方法时生成对象 PromiseReaction1,此时 myPromise4 的 reactionsorresult 存的是 PromiseReaction1。

    第二次调用 then 方法时生成对象 PromiseReaction2,调用 NewPromiseReaction 函数时,PromiseReaction2.next = PromiseReaction1,PromiseReaction1 变成了 PromiseReaction2 的下一个节点,最后 myPromise4 的 reactionsorresult 存的是 PromiseReaction2。PromiseReaction2 后进入 Promise 处理函数的链表,却是链表的头结点。NewPromiseReaction 函数源码如下:

    1. macro NewPromiseReaction(implicit context: Context)(

    2. handlerContext: Context, next: Zero|PromiseReaction,

    3. promiseOrCapability: JSPromise|PromiseCapability|Undefined,

    4. fulfillHandler: Callable|Undefined,

    5. rejectHandler: Callable|Undefined): PromiseReaction {

    6. const nativeContext = LoadNativeContext(handlerContext);

    7. return new PromiseReaction{

    8. map: PromiseReactionMapConstant(),

    9. next: next, // next 字段存的是链表中的下一个节点

    10. reject_handler: rejectHandler,

    11. fulfill_handler: fulfillHandler,

    12. promise_or_capability: promiseOrCapability,

    13. continuation_preserved_embedder_data: nativeContext

    14. [NativeContextSlot::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX]

    15. };

    16. }

    在 myPromise4 处于 pending 状态时,myPromise4 的 reactionsorresult 字段示意如下图,下图不是 microtask 队列,下图不是 microtask 队列,下图不是 microtask 队列。

    3.2.2 PerformPromiseThenImpl 函数的 fulfilled/rejected 分支

    fulfilled/rejected 分支逻辑则简单的多,处理的是当 Promise 处于 fulfilled/rejected 状态时,调用 then 方法的逻辑,以 fulfilled 状态为例,调用 NewPromiseFulfillReactionJobTask 生成 microtask,然后 EnqueueMicrotask(handlerContext, microtask) 将刚才生成的 microtask 放入 microtask 队列。

    1. new Promise((resolve, reject) => {

    2. resolve()

    3. }).then(result => {

    4. console.log('进入 microtask 队列后执行')

    5. })

    6. console.log('同步执行结束')

    7. // 本段代码的打印顺序是:

    8. // 同步执行结束、

    9. // 进入 microtask 队列后执行

    尽管调用 then 方法时,Promise 已经处于 resolved 状态,但 then 方法的 onFulfilled 回调函数不会立即执行,而是进入 microtask 队列后执行。

    对于一个已经 fulfilled 状态的 Promise,调用其 then 方法时,then 方法接收的 onFulfilled 回调函数不会立即执行。而是进入 microtask 队列后执行,rejected 状态同理 then 方法做的事情简单说就是依赖收集,当 Promise 变成 fulfilled/rejected 状态时,会触发之前收集到的依赖

    4.resolve

    resolve 函数归根到底调用了 V8 的 FulfillPromise 函数,源码如下:

    1. // https://tc39.es/ecma262/#sec-fulfillpromise

    2. transitioning builtin

    3. FulfillPromise(implicit context: Context)(

    4. promise: JSPromise, value: JSAny): Undefined {

    5. // Assert: The value of promise.[[PromiseState]] is "pending".

    6. // promise 的状态改变是不可逆的

    7. assert(promise.Status() == PromiseState::kPending);

    8. // 取 Promise 的处理函数

    9. const reactions =

    10. UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result);

    11. // Promise 已处于 fulfilled 状态,reactions_or_result 存储的不再是

    12. // 处理函数,而是 Promise 的结果

    13. promise.reactions_or_result = value;

    14. // 设置 Promise 的状态为 fulfilled

    15. promise.SetStatus(PromiseState::kFulfilled);

    16. // Promise 的处理函数,Promise 的结果都拿到了,开始正式处理

    17. TriggerPromiseReactions(reactions, value, kPromiseReactionFulfill);

    18. return Undefined;

    19. }

    FulfillPromise 的逻辑是获取 Promise 的处理函数到 reactions,reactions 的类型是 PromiseReaction,是个链表,忘记的同学可以回看上节的那张链表图片;设置 promise 的 reactionsorresult 为 value,这个 value 就是 JavaScript 层传给 resolve 的参数;调用 promise.SetStatus 设置 promise 的状态为 PromiseState::kFulfilled,最后调用 TriggerPromiseReactions。源码如下:

    1. // https://tc39.es/ecma262/#sec-triggerpromisereactions

    2. transitioning macro TriggerPromiseReactions(implicit context: Context)(

    3. reactions: Zero|PromiseReaction, argument: JSAny,

    4. reactionType: constexpr PromiseReactionType): void {

    5. // We need to reverse the {reactions} here, since we record them on the

    6. // JSPromise in the reverse order.

    7. let current = reactions;

    8. let reversed: Zero|PromiseReaction = kZero;

    9. // 链表反转

    10. while (true) {

    11. typeswitch (current) {

    12. case (Zero): {

    13. break;

    14. }

    15. case (currentReaction: PromiseReaction): {

    16. current = currentReaction.next;

    17. currentReaction.next = reversed;

    18. reversed = currentReaction;

    19. }

    20. }

    21. }

    22. // Morph the {reactions} into PromiseReactionJobTasks and push them

    23. // onto the microtask queue.

    24. current = reversed;

    25. // 链表反转后,调用 MorphAndEnqueuePromiseReaction,把链接中的每一项都进入 microtask 队列

    26. while (true) {

    27. typeswitch (current) {

    28. case (Zero): {

    29. break;

    30. }

    31. case (currentReaction: PromiseReaction): {

    32. current = currentReaction.next;

    33. MorphAndEnqueuePromiseReaction(currentReaction, argument, reactionType);

    34. }

    35. }

    36. }

    37. }

    TriggerPromiseReactions 做了两件事:

    反转 reactions 链表,前文有分析过 then 方法的实现,then 方法的参数最终存在链表中。最后被调用的 then 方法,它接收的参数被包装后会位于链表的头部,这不符合规范,所以需要反转

    遍历 reactions 对象,将每个元素放入 microtask 队列

    1. const myPromise4 = new Promise((resolve, reject) => {

    2. setTimeout(_ => {

    3. resolve('my code delay 5000')

    4. }, 5e3)

    5. })

    6. myPromise4.then(result => {

    7. console.log('第 1 个 then')

    8. })

    9. myPromise4.then(result => {

    10. console.log('第 2 个 then')

    11. })

    12. // 打印顺序:

    13. // 第 1 个 then

    14. // 第 2 个 then

    15. // 如果把 TriggerPromiseReactions 中链表反转的代码注释掉,打印顺序为

    16. // 第 2 个 then

    17. // 第 1 个 then

    resolve 的主要工作是遍历上节调用 then 方法时收集到的依赖,放入 microtask 队列中

  • 相关阅读:
    Android布局1
    QML 自定义折线图
    QML ChartView 画折线图
    操作系统复习笔记
    Redis的使用
    Git的基本使用
    Python json to excel/csv
    .NET中进行Base64加密解密
    用 IIS 7、ARR 與 Velocity 建设高性能的大型网站
    微信突然出现redirect_uri 参数错误
  • 原文地址:https://www.cnblogs.com/zhouyideboke/p/13825837.html
Copyright © 2011-2022 走看看