Node.js v18.18.2 文档


目录

C++ 嵌入 API#

Node.js 提供了许多 C++ API,可用于在 Node.js 环境中从其他 C++ 软件执行 JavaScript。

这些 API 的文档可以在Node.js 源代码树的src/node.h中找到。除了 Node.js 公开的 API 之外,V8 嵌入 API 还提供了一些必需的概念。

由于使用 Node.js 作为嵌入式库与编写由 Node.js 执行的代码不同,因此重大更改不遵循典型的 Node.js 弃用策略,并且可能会在每个 semver-major 版本上发生,而不会事先发出警告。

嵌入应用示例#

以下部分将概述如何使用这些 API 从头开始​​创建一个应用程序,该应用程序将执行与node -e <code>等效的操作 ,即,将采用一段 JavaScript 并在 Node.js 中运行它-特定环境。

完整的代码可以在 Node.js 源代码树中找到。

设置每个进程的状态#

Node.js 需要一些每个进程的状态管理才能运行:

  • Node.js CLI 选项的参数解析,
  • V8 每个进程的要求,例如v8::Platform实例。

以下示例显示了如何设置它们。一些类名分别来自nodev8 C++ 命名空间。

int main(int argc, char** argv) {
  argv = uv_setup_args(argc, argv);
  std::vector<std::string> args(argv, argv + argc);
  // Parse Node.js CLI options, and print any errors that have occurred while
  // trying to parse them.
  std::unique_ptr<node::InitializationResult> result =
      node::InitializeOncePerProcess(args, {
        node::ProcessInitializationFlags::kNoInitializeV8,
        node::ProcessInitializationFlags::kNoInitializeNodeV8Platform
      });

  for (const std::string& error : result->errors())
    fprintf(stderr, "%s: %s\n", args[0].c_str(), error.c_str());
  if (result->early_return() != 0) {
    return result->exit_code();
  }

  // Create a v8::Platform instance. `MultiIsolatePlatform::Create()` is a way
  // to create a v8::Platform instance that Node.js can use when creating
  // Worker threads. When no `MultiIsolatePlatform` instance is present,
  // Worker threads are disabled.
  std::unique_ptr<MultiIsolatePlatform> platform =
      MultiIsolatePlatform::Create(4);
  V8::InitializePlatform(platform.get());
  V8::Initialize();

  // See below for the contents of this function.
  int ret = RunNodeInstance(
      platform.get(), result->args(), result->exec_args());

  V8::Dispose();
  V8::DisposePlatform();

  node::TearDownOncePerProcess();
  return ret;
} 

每个实例的状态#

Node.js 有一个“Node.js 实例”的概念,通常称为node::Environment。每个node::Environment都与:

  • 正好一个v8::Isolate,即一个 JS Engine 实例,
  • 正好一个uv_loop_t,即一个事件循环,并且
  • 许多v8::Context,但只有一个主要的v8::Context
  • 一个node::IsolateData实例,包含可由使用相同v8::Isolate 的多个 node::Environment共享的信息。目前,没有针对此场景进行测试。

为了设置v8::Isolate,需要提供v8::ArrayBuffer::Allocator 。一种可能的选择是默认的 Node.js 分配器,它可以通过node::ArrayBufferAllocator::Create()创建。当插件使用 Node.js C++ Buffer API时,使用 Node.js 分配器可以实现较小的性能优化,并且是跟踪process.memoryUsage() 中的ArrayBuffer内存 所必需的。

此外,用于 Node.js 实例的每个v8::Isolate 都需要向MultiIsolatePlatform实例(如果正在使用)进行注册和注销,以便平台能够知道哪个事件循环用于由v8::Isolate安排的任务。

node::NewIsolate()辅助函数创建一个v8::Isolate,使用一些特定于 Node.js 的挂钩(例如 Node.js 错误处理程序)对其进行设置,并自动将其注册到平台。

int RunNodeInstance(MultiIsolatePlatform* platform,
                    const std::vector<std::string>& args,
                    const std::vector<std::string>& exec_args) {
  int exit_code = 0;

  // Setup up a libuv event loop, v8::Isolate, and Node.js Environment.
  std::vector<std::string> errors;
  std::unique_ptr<CommonEnvironmentSetup> setup =
      CommonEnvironmentSetup::Create(platform, &errors, args, exec_args);
  if (!setup) {
    for (const std::string& err : errors)
      fprintf(stderr, "%s: %s\n", args[0].c_str(), err.c_str());
    return 1;
  }

  Isolate* isolate = setup->isolate();
  Environment* env = setup->env();

  {
    Locker locker(isolate);
    Isolate::Scope isolate_scope(isolate);
    HandleScope handle_scope(isolate);
    // The v8::Context needs to be entered when node::CreateEnvironment() and
    // node::LoadEnvironment() are being called.
    Context::Scope context_scope(setup->context());

    // Set up the Node.js instance for execution, and run code inside of it.
    // There is also a variant that takes a callback and provides it with
    // the `require` and `process` objects, so that it can manually compile
    // and run scripts as needed.
    // The `require` function inside this script does *not* access the file
    // system, and can only load built-in Node.js modules.
    // `module.createRequire()` is being used to create one that is able to
    // load files from the disk, and uses the standard CommonJS file loader
    // instead of the internal-only `require` function.
    MaybeLocal<Value> loadenv_ret = node::LoadEnvironment(
        env,
        "const publicRequire ="
        "  require('node:module').createRequire(process.cwd() + '/');"
        "globalThis.require = publicRequire;"
        "require('node:vm').runInThisContext(process.argv[1]);");

    if (loadenv_ret.IsEmpty())  // There has been a JS exception.
      return 1;

    exit_code = node::SpinEventLoop(env).FromMaybe(1);

    // node::Stop() can be used to explicitly stop the event loop and keep
    // further JavaScript from running. It can be called from any thread,
    // and will act like worker.terminate() if called from another thread.
    node::Stop(env);
  }

  return exit_code;
} 

NodeJS中文文档为Read dev Docs平台提供托管,中文NodeJS文档均由英文版NodeJS文档翻译,版权属于nodejs.org