0
点赞
收藏
分享

微信扫一扫

Promise V8 一源码分析------------引用

            本文基于 node 版本 14.13.0,V8 版本 8.4.371。Promise 源码全部位于 V8

1.基本数据结构

  Promise 共有 3 种状态,源码如下 

1. ​​// Promise constants​​
2. ​​extern enum PromiseState extends int31 constexpr 'Promise::PromiseState' {​​
3. ​​ kPending,​​
4. ​​ kFulfilled,​​
5. ​​ kRejected​​
6. ​​}​​

一个新创建的 Promise 处于 pending 状态。当调用 resolve 或 reject 函数后,Promise 处于 fulfilled 或 rejected 状态,此后 Promise 的状态保持不变,也就是说 Promise 的状态改变是不可逆的,Promise 源码中出现了多处状态相关的 assert。

1.2 JSPromise

JSPromise 描述 Promise 的基本信息,源码如下:

1. ​​bitfield struct JSPromiseFlags extends uint31 {​​
2. ​​ status: PromiseState: 2 bit; // Promise 的状态,kPending/kFulfilled/kRejected​​
3. ​​ has_handler: bool: 1 bit; // 是否有处理函数,没有调用过 then 方法的 Promise 没有处理函数​​
4. ​​ handled_hint: bool: 1 bit;​​
5. ​​ async_task_id: int32: 22 bit;​​
6. ​​}​​

 

大意是说处于 rejected 状态的 Promise 必须要有处理函数。V8 通过 HasHandler 判断 myPromise1 并没有处理函数。当把处理函数加上以后,代码如下:

1. @generateCppClass​​
2. ​​extern class JSPromise extends JSObject {​​
3. ​​ macro Status(): PromiseState {​​
4. ​​ // 获取 Promise 的状态,返回 kPending/kFulfilled/kRejected 中的一个​​
5. ​​ return this.flags.status;​​
6. ​​ }​​
7.
8. ​​ macro SetStatus(status: constexpr PromiseState): void {​​
9. ​​ // 第 1 个 assert 表示只有 pending 状态的 Promise 才可以被改变状态​​
10. ​​ assert(this.Status() == PromiseState::kPending);​​
11. ​​ // 第 2 个 assert 表示 Promise 创建成功后,不可将 Promise 设置为 pending 状态​​
12. ​​ assert(status != PromiseState::kPending);​​
13. ​​ this.flags.status = status;​​
14. ​​ }​​
15.
16. ​​ macro HasHandler(): bool {​​
17. ​​ // 判断 Promise 是否有处理函数​​
18. ​​ return this.flags.has_handler;​​
19. ​​ }​​
20.
21. ​​ macro SetHasHandler(): void {​​
22. ​​ this.flags.has_handler = true;​​
23. ​​ }​​
24.
25. ​​ // Smi 0 terminated list of PromiseReaction objects in case the JSPromise was​​
26. ​​ // not settled yet, otherwise the result.​​
27. ​​ // promise 处理函数或结果,可以是无/包装了 onFulfilled/onRejected 回调函数的对象/resolve 接收的参数​​
28. ​​ reactions_or_result: Zero|PromiseReaction|JSAny;​​
29. ​​ flags: SmiTagged<JSPromiseFlags>;​​

 

此时 SetHasHandler 已被调用,HasHandler 返回 true 表示 myPromise1 有处理函数。在 node-v14.13.0 环境下执行,没有错误提示,一切正常

1. const myPromise1 = new Promise((resolve, reject) => {​​
2. ​​ reject()​​
3. ​​})​​
4.
5. ​​myPromise1.then(console.log, console.log)​​

1.3 其它
  • executor:是函数,Promise 构造函数接收的参数
  • PromiseReaction:是对象,表示 Promise 的处理函数,因为一个 Promise 多次调用 then 方法就会有多个处理函数,所以底层数据结构是个链表。

2.构造函数

构造函数源码如下

首先分析两个 ThrowTypeError,以下代码可触发第一个 ThrowTypeError。

1. / https://tc39.es/ecma262/#sec-promise-executor​​
2. ​​transitioning javascript builtin​​
3. ​​PromiseConstructor(​​
4. ​​ js-implicit context: NativeContext, receiver: JSAny,​​
5. ​​ newTarget: JSAny)(executor: JSAny): JSAny {​​
6. ​​ // 1. If NewTarget is undefined, throw a TypeError exception.​​
7. ​​ if (newTarget == Undefined) {​​
8. ​​ ThrowTypeError(MessageTemplate::kNotAPromise, newTarget);​​
9. ​​ }​​
10.
11. ​​ // 2. If IsCallable(executor) is false, throw a TypeError exception.​​
12. ​​ if (!Is<Callable>(executor)) {​​
13. ​​ ThrowTypeError(MessageTemplate::kResolverNotAFunction, executor);​​
14. ​​ }​​
15.
16. ​​ let result: JSPromise;​​
17. ​​ // 构造一个 Promise 对象​​
18. ​​ result = NewJSPromise();​​
19. ​​ // 从 Promise 对象 result 身上,获取它的 resolve 和 reject 函数​​
20. ​​ const funcs = CreatePromiseResolvingFunctions(result, True, context);​​
21. ​​ const resolve = funcs.resolve;​​
22. ​​ const reject = funcs.reject;​​
23. ​​ try {​​
24. ​​ // 直接同步调用 executor 函数,resolve 和 reject 做为参数​​
25. ​​ Call(context, UnsafeCast<Callable>(executor), Undefined, resolve, reject);​​
26. ​​ } catch (e) {​​
27. ​​ Call(context, reject, Undefined, e);​​
28. ​​ }​​
29. ​​ return result;​​
30. ​​}​​

  1. ​Promise() // Uncaught TypeError: undefined is not a promise​

原因是没有使用 new 操作符调用 Promise 构造函数,此时 newTarget 等于 Undefined,触发了 ThrowTypeError(MessageTemplate::kNotAPromise, newTarget)。

以下代码可触发第二个 ThrowTypeError

  1. ​new Promise() // Uncaught TypeError: Promise resolver undefined is not a function​

此时 newTarget 不等于 Undefined,不会触发第一个 ThrowTypeError。但调用 Promise 构造函数时没传参数 executor,触发了第二个 ThrowTypeError。

错误消息在 C++ 代码中定义,使用了宏和枚举巧妙的生成了 C++ 代码,这里不做展开,源码如下

1. ​​T(NotAPromise, "% is not a promise") \​​
2. ​​T(ResolverNotAFunction, "Promise resolver % is not a function") \​​

  executor 的类型是函数,在 JavaScript 的世界里,回调函数通常是异步调用,但 executor 是同步调用。在 Call(context, UnsafeCast(executor), Undefined, resolve, reject) 这一行,同步调用了 executor。

Promise 构造函数接收的参数 executor,是被同步调用的

1. console.log('同步执行开始')​​
2. ​​new Promise((resolve, reject) => {​​
3. ​​ resolve()​​
4. ​​ console.log('executor 同步执行')​​
5. ​​})​​
6.
7. ​​console.log('同步执行结束')​​
8. ​​// 本段代码的打印顺序是:​​
9. ​​// 同步执行开始​​
10. ​​// executor 同步执行​​
11. ​​// 同步执行结束​​

Promise 构造函数调用 NewJSPromise 获取一个新的 JSPromise 对象。NewJSPromise 调用 PromiseInit 来初始化一个 JSPromise 对象,源码如下

 

3.then

1. 
2. ​​macro PromiseInit(promise: JSPromise): void {​​
3. ​​ promise.reactions_or_result = kZero;​​
4. ​​ promise.flags = SmiTag(JSPromiseFlags{​​
5. ​​ status: PromiseState::kPending,​​
6. ​​ has_handler: false,​​
7. ​​ handled_hint: false,​​
8. ​​ async_task_id: 0​​
9. ​​ });​​
10. ​​ promise_internal::ZeroOutEmbedderOffsets(promise);​​

3.1 PromisePrototypeThen

JavaScript 层的 then 函数实际上是 V8 中的 PromisePrototypeThen 函数

 

1. ​​transitioning javascript builtin​​
2. ​​PromisePrototypeThen(js-implicit context: NativeContext, receiver: JSAny)(​​
3. ​​ onFulfilled: JSAny, onRejected: JSAny): JSAny {​​
4. ​​ // 1. Let promise be the this value.​​
5. ​​ // 2. If IsPromise(promise) is false, throw a TypeError exception.​​
6. ​​ const promise = Cast<JSPromise>(receiver) otherwise ThrowTypeError(​​
7. ​​ MessageTemplate::kIncompatibleMethodReceiver, 'Promise.prototype.then',​​
8. ​​ receiver);​​
9.
10. ​​ // 3. Let C be ? SpeciesConstructor(promise, %Promise%).​​
11. ​​ const promiseFun = UnsafeCast<JSFunction>(​​
12. ​​ context[NativeContextSlot::PROMISE_FUNCTION_INDEX]);​​
13.
14. ​​ // 4. Let resultCapability be ? NewPromiseCapability(C).​​
15. ​​ let resultPromiseOrCapability: JSPromise|PromiseCapability;​​
16. ​​ let resultPromise: JSAny;​​
17. ​​ label AllocateAndInit {​​
18. ​​ const resultJSPromise = NewJSPromise(promise);​​
19. ​​ resultPromiseOrCapability = resultJSPromise;​​
20. ​​ resultPromise = resultJSPromise;​​
21. ​​ }​​
22. ​​ // onFulfilled 和 onRejected 是 then 接收的两个参数​​
23. ​​ const onFulfilled = CastOrDefault<Callable>(onFulfilled, Undefined);​​
24. ​​ const onRejected = CastOrDefault<Callable>(onRejected, Undefined);​​
25.
26. ​​ // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected,​​
27. ​​ // resultCapability).​​
28. ​​ PerformPromiseThenImpl(​​
29. ​​ promise, onFulfilled, onRejected, resultPromiseOrCapability);​​
30. ​​ // 返回一个新的 Promise​​
31. ​​ return resultPromise;​​
32. ​​}​​

PromisePrototypeThen 函数创建了一个新的 Promise,获取 then 接收到的两个参数,调用 PerformPromiseThenImpl 完成大部分工作。这里有一点值得注意,then 方法返回的是一个新创建的 Promise。

1. ​​const myPromise2 = new Promise((resolve, reject) => {​​
2. ​​ resolve('foo')​​
3. ​​})​​
4.
5. ​​const myPromise3 = myPromise2.then(console.log)​​
6.
7. ​​// myPromise2 和 myPromise3 是两个不同的对象,有不同的状态和不同的处理函数​​
8. ​​console.log(myPromise2 === myPromise3) // 打印 false​​

       then 方法返回的是一个新的 Promise

 



举报

相关推荐

0 条评论