暂无个人介绍
2024年06月
AsyncHook 在 Node.js 中扮演了注册异步事件生命周期的不同阶段(如初始化、执行前、执行后、销毁等)回调函数的角色。通过 AsyncHook,开发者可以在这些异步事件的生命周期中插入自定义逻辑。
在 Node.js 的 C++ 层,AsyncWrap 类在 async_wrap.cc 文件中定义,它继承自 BaseObject。AsyncWrap 类是一个基类,用于触发异步事件的钩子(hooks)回调。其他特定的包装类(如 UPDWrap、TCPWrap 等)直接或间接继承自 AsyncWrap,并为各种包装提供了触发钩子回调的方法。
internalBinding 方法是 Node.js 的一个内部机制,用于从 JavaScript 层加载 C++ 绑定模块。它允许 JavaScript 代码直接访问这些 C++ 模块提供的 API。internalBinding 方法在 lib/internal/bootstrap/loader.js 文件中定义,并在 Node.js 启动时被加载到全局作用域中,因此不需要使用 require 来引入。
AsyncLocalStorage 的性能改进是通过使用栈(stack)而不是 AsyncResource 实例来实现的。这种方法消除了额外的生命周期事件,从而提高了性能。这个改进可以在 Node.js 的 GitHub 仓库中的一个 Pull Request(PR #39890)中找到。
PromiseHook 是 Node.js 中用于监听 Promise 生命周期事件的一个特性。它与 AsyncHook 没有直接的关系,但都是 Node.js 提供的用于监控异步操作的工具。然而,随着 Node.js 的发展,对 Promise 生命周期的监控也进行了优化,例如通过 PR #32891 引入的快速路径(fast-path)来改进性能。
lib/internal/bootstrap/loader.js 文件在 Node.js 中负责创建内部模块和绑定的加载器(loaders)。这些加载器用于加载 Node.js 的内置模块和 C++ 绑定,以便在 JavaScript 层使用。这个文件在 Node.js 启动时被编译和运行,因此在 Node.js 实际启动之前,这些加载器就已经被引导(bootstrapped)。
AsyncLocalStorage 的性能是通过 PR #39890 得到改进的,主要方法是使用栈(stack)来代替 AsyncResource 实例,从而消除了额外的生命周期事件。
PromiseHook 不是直接与 AsyncHook 相关的特性,但两者都是 Node.js 提供的用于监控异步操作的工具。PromiseHook 专注于监听 Promise 生命周期事件。
Node.js 中的 loader 是通过 lib/internal/bootstrap/loader.js 文件创建的。这个文件在 Node.js 启动之前由 node.cc 编译和运行,负责创建内部模块和绑定的加载器。
Node.js 的性能改进 PR 可能会因为各种原因被关闭,但代码改动可能通过 Node.js 的内部流程被合并到某个版本中,如 Node v16.18。Node.js 的发版和代码管理有其自己的流程,不完全依赖于 GitHub 的 PR 系统。
Node.js 中的 API 是通过内部模块和绑定(bindings)暴露给 JavaScript 层的。对于内部模块,如 async_hooks.js,它们通过 JavaScript 代码直接暴露 API。对于绑定,如 async_wrap,它们通过 C++ 代码编写,并使用如 NODE_MODULE_CONTEXT_AWARE_INTERNAL 这样的宏来注册,然后通过 internalBinding 方法在 JavaScript 层访问。
Local 在 V8 中代表一个指向 JavaScript 函数对象的句柄。这个句柄是轻量级的,用于在 C++ 层引用和管理 JavaScript 函数对象。通过这个句柄,C++ 代码可以调用 JavaScript 函数。
EmitAsyncInit 方法首先检查是否有任何 AsyncHook 的 init 回调函数被注册。如果有,它会从 Environment 实例中获取这个回调函数,并使用 V8 的 API(Function::Call)来调用它。调用时,传递了相关的参数,如异步事件的 ID、类型等。
SetupHooks 方法从传入的参数中获取一个包含所有 AsyncHook 回调函数的对象。然后,它使用宏 SET_HOOK_FN 来遍历这个对象,并将每个回调函数绑定到对应的 Environment 实例的属性上,以便后续在 C++ 层调用。
Node.js 通过调用 internalBinding('async_wrap').setupHooks(nativeHooks); 将 JavaScript 层的 nativeHooks 对象注册到 C++ 层的 async_wrap 模块。在 C++ 层,这个注册过程是通过 AsyncWrap::Initialize 函数中的 SetupHooks 方法实现的。
emitInitNative 函数的作用是从 C++ 层调用所有已注册的 AsyncHook 的 init 回调函数。它遍历 active_hooks.array 数组,并调用每个 AsyncHook 实例的 init 方法。
active_hooks.array 是在 lib/internal/async_hooks.js 文件中定义的,它是一个数组,用于存储当前被启用的所有 AsyncHook 实例。当异步事件触发时,Node.js 会遍历这个数组,并调用每个 AsyncHook 实例中注册的相关回调函数。
AsyncHook 的 init 方法被存储在 AsyncHook 类的实例属性中,具体是通过 this[init_symbol] = init; 这样的方式存储的,其中 init_symbol 是一个 Symbol 类型的属性键。当 AsyncHook 实例被启用(enable)时,这些回调函数被添加到 active_hooks.array 数组中。
ibuv 中的 "uv" 并不是指每日访问量 UV 或 DAU,而是 "Lib of Unicorn Velociraptor" 的缩写,意为“独角兽迅猛龙的库”。这个名称来源于 libuv 的 logo 设计。
尽管在 async_wrap.cc 文件中没有直接引用 libuv 的头文件(如 uv.h),但 async_wrap 模块通过 Node.js 的内部机制与 libuv 交互。具体来说,async_wrap 模块可能作为基类提供 API 与 JavaScript 层交互,而其子类可能与 libuv 的 uv_handle_t 类型进行交互,以在异步操作的不同阶段执行相应的回调。这种交互是通过 Node.js 的内部 API 进行的,而不是直接在 async_wrap.cc 文件中调用 libuv 的 API。