jsernews 1.0.1

<~>

ts 217 days ago.

原文链接:https://blog.safia.rocks/post/169543119660/how-does-processbinding-in-node-work

这篇文章的另一个标题是:走入 V8 虫洞。想知道为什么?请继续阅读!

所以关于我现在一直在做的这些 Node 模块深入系列,有一段时间了。

在我的最近一篇文章中,我介绍了代码库的 C 部分,并简要地提到了 process.binding 以及它如何用于将内部模块(用 C 编写)公开给 Node。我很好奇这是如何工作的细节,所以我决定深入研究它。

我开始通过谷歌搜索 “what is process.binding node”,并找出这方面的现有材料。我发现这个由 Lance Ball 制作的相当有用的幻灯片。有趣的部分从幻灯片12开始,它概述了“Node.js main 函数获取一个进程对象”。我决定去找到与此说法相关的代码。这个幻灯片大约发布于3年前,所以我不得不做一些挖掘以找到实际提到的代码行。我尽我所能,但我无法找到 Node 进程初始化的入口点,如该幻灯片中引用的那样。

我想知道在过去的三年中,初始化是否已经转移到代码库的非 JavaScript 部分。也许 Node 进程及其依赖完全通过 C++ 扩展初始化?我不确定。如果您对此有任何见解,请告诉我。

下一张幻灯片讨论了如何使用 C++ 初始化 Process 对象,并且附带了一些基本属性。果然,我在这里找到了代码。Lance 在幻灯片中提到的代码已经改变了很多,所以让我们来看看它。

void SetupProcessObject(const FunctionCallbackInfo<value>& args) {
  Environment* env = Environment::GetCurrent(args);

  CHECK(args[0]->IsFunction());

  env->set_push_values_to_array_function(args[0].As<function>());
  env->process_object()->Delete(
      env->context(),
      FIXED_ONE_BYTE_STRING(env->isolate(), "_setupProcessObject")).FromJust();
}

好!所以它看起来像 SetupProcessObject 函数接受一个回调作为参数并配置传递给它的“环境”。我想要做的第一件事是弄清楚 Environment::GetCurrent(args) 究竟做了什么。这个函数调用在这个文件中被使用了很多次,我认为弄清楚它究竟做了什么是很有用的。我试图检查 node.cc 文件的头文件,以查看它是否对某种 envenvironment 文件进行了引用。果然,有一个 env-inl.h 头文件的引用,所以我找到了,并在这里找到它。它定义了几个 GetCurrent 函数,每个函数都接收不同类型的参数。我试图找到带有 FunctionCallbackInfo<value> 参数的 GetCurrent 函数,类似于上面代码片段中传递给它的那个,然后找到以下内容。

inline Environment* Environment::GetCurrent(
    const v8::FunctionCallbackInfo<:value>& info) {
  CHECK(info.Data()->IsExternal());
  return static_cast<environment>(info.Data().As<:external>()->Value());
}

所以它看起来像这个函数正在做的是使用 Data() 函数从 info 对象中提取一些数据,并以 v8:External 的数据类型返回值。我以前从来没有见过 static_cast 运算符,所以我做了一些研究,发现它负责进行显式类型转换。这证实了我的假设,即此函数主要负责从 FunctionCallbackInfo 对象中提取有关当前 Node 运行环境的详细信息,并将其作为 Enviroment 类型返回。无论如何,我现在对所有这些 Enviroment 内容都没有兴趣。我特别好奇的是这里的下一行。

  env->process_object()->Delete(
      env->context(),
      FIXED_ONE_BYTE_STRING(env->isolate(), "_setupProcessObject")).FromJust();
}

好!所以看起来这一行从环境中提取 “process_object” 并 Delete 它中的某些东西。我查看了代码库,发现 process_object() 函数返回一个 Local<object> 类型的对象。从一些窥探中,我发现这个 Local<object> 是一个在V8库,JavaScript 引擎中定义的类型。查看一些文档,我发现 Local<object> 是V8中的其他对象(如 Date 对象和 Number 对象)从中继承的对象。

接下来我想弄清楚 env->context() 是什么。从代码库中的一些头文件的一些窥探中,我发现它是一个 v8:Context 对象。我读了更多的文档,发现 Node 似乎使用了Context 对象来维护关于当前正在运行的进程的基本配置细节,比如安装了什么扩展。

代码的下一部分很有趣,如下的一小段。

FIXED_ONE_BYTE_STRING(env->isolate(), "_setupProcessObject")

第一件事我想弄清楚 FIXED_ONE_BYTE_STRING 究竟做了什么。鉴于名称,我的怀疑是它根据给定的参数生成固定长度的字符串。第二个参数显然是一个字符串,所以没有太多的挖掘,但我对第一个 env->isolate() 很好奇。当我在代码库的不同部分读了更多代码后,发现 env->isolate() 可能代表了 V8:Isolate 对象,您可以在这里阅读更多信息。

好吧,我经历了很多虫洞,并没有真正发现我需要知道的东西(我们是否真的找到了我们需要知道的东西?)。我将做更多的阅读并更好地理解用于 Node 和 V8 之间桥梁的探索性路线图。现在的好处是,我觉得在探索 V8 和 Node 之间的桥梁时会更加舒适。对我而言,这是一个不稳定和令人紧张的问题但我正在慢慢开始弄清楚。向前!

如果你对 V8 的源码有更多的了解,并想澄清我上面提到的任何事情,请告诉我。