- 适用于 JDK 23 的 GraalVM(最新版)
- 适用于 JDK 24 的 GraalVM(抢先体验版)
- 适用于 JDK 21 的 GraalVM
- 适用于 JDK 17 的 GraalVM
- 存档
- 开发版
Node.js 运行时
GraalVM 可以运行未修改的 Node.js 应用程序。GraalVM 的 Node.js 运行时基于最新的 Node.js 版本,并运行 GraalVM JavaScript 引擎(GraalJS)而不是 Google V8。某些内部功能(例如,VM 内部统计信息、配置、分析、调试等)不受支持,或支持的行为可能不同。
应用程序可以自由地导入和使用 NPM 包,包括原生包。
Node.js 入门 #
从适用于 JDK 21 的 GraalVM 开始,GraalVM Node.js 运行时作为单独的发布版提供。两种独立的运行时选项可用于 Oracle GraalVM 和 GraalVM 社区版:使用原生镜像编译的启动器或基于 JVM 的运行时。为了区分两者,GraalVM 社区版的版本名称中带有后缀 -community
:graaljs-community-<version>-<os>-<arch>.tar.gz
、graalnodejs-community-<version>-<os>-<arch>.tar.gz
。带有 JVM 的独立版在名称中带有后缀 -jvm
。
要启用 GraalVM Node.js 运行时,请安装基于 Oracle GraalVM 或 GraalVM 社区版,适合您操作系统的 Node.js 发布版。
-
导航到 GitHub 发布版 并选择适合您操作系统的独立版。
- 解压缩归档文件
tar -xzf <archive>.tar.gz
或者,在 Finder 中打开该文件。
- 检查版本以查看运行时是否已激活
./path/to/bin/node --version
运行 Node.js 应用程序 #
Node.js 安装提供了 node
和 npm
启动器
node [options] [filename] [args]
npm
命令等效于默认的 Node.js 命令,并具有额外的 GraalVM 特定功能(例如,与 Java 的互操作性)。可以使用 node --help
获取可用选项列表。
使用 node
启动器执行 Node.js 应用程序。例如
- 使用
npm install
安装colors
和ansispan
包,如下所示npm install colors ansispan
安装完包后,就可以在应用程序中使用它们了。
- 将以下代码片段添加到名为 app.js 的文件中,并将其保存在安装 Node.js 包的同一目录中
const http = require("http"); const span = require("ansispan"); require("colors"); http.createServer(function (request, response) { response.writeHead(200, {"Content-Type": "text/html"}); response.end(span("Hello Node.js!".green)); }).listen(8000, function() { console.log("Node.js server running at http://127.0.0.1:8000/".red); }); setTimeout(function() { console.log("DONE!"); process.exit(); }, 2000);
- 使用
node
命令在 GraalVM Node.js 运行时执行它,如下所示node app.js
当应用程序从 node
二进制启动器启动时,Node.js 功能可用。从 Java 上下文启动 Node.js 应用程序或访问 NPM 包时,会应用某些限制,请参阅 Node.js 与 Java 脚本上下文。
使用 npm
安装包 #
要安装 Node.js 包,请使用 npm
启动器。npm
命令等效于默认的 NPM 命令,并支持其大多数选项。
可以使用以下命令安装 NPM 包
npm install [package]
由于 GraalVM Node.js 的 npm
命令与 NPM 很大程度上兼容,因此包将按预期安装在 node_modules/ 目录中。
全局安装 npm
包 #
可以使用 npm
和 -g
选项全局安装 Node 包。默认情况下,npm
在安装 node
可执行文件的路径(通常为 node/bin/)中安装全局包(指向其可执行文件的链接)。该目录是全局包的安装位置。如果您经常使用全局安装的包,尤其是它们的命令行界面,您可能需要将该目录添加到 $PATH
中。
另一种方法是通过设置 $PREFIX
环境变量,或在运行 npm install
时指定 --prefix
选项,来指定 npm
的全局安装目录。例如,以下命令将在 /foo/bar/ 目录中安装全局包
npm install --prefix /foo/bar -g <package>
有关 prefix
的更多详细信息,请参阅 官方 NPM 文档。
与 Java 的互操作性 #
Node.js 运行时不能嵌入到 JVM 中,而必须作为单独的进程启动。
- 将以下代码保存在名为 HelloPolyglot.java 的文件中并编译
import org.graalvm.polyglot.*; import org.graalvm.polyglot.proxy.*; public class HelloPolyglot { static String JS_CODE = "(function myFun(param){console.log('hello '+param);})"; public static void main(String[] args) { System.out.println("Hello Java!"); try (Context context = Context.create()) { Value value = context.eval("js", JS_CODE); value.execute(args[0]); } } }
- 然后将此代码保存在名为 app.js 的文件中
var HelloPolyglot = Java.type("HelloPolyglot"); HelloPolyglot.main(["from node.js"]); console.log("done");
- 使用
node
运行它node --vm.cp=. app.js
您应该看到以下输出
Hello Java! hello from node.js done
然后,Node.js 和 JVM 在同一进程中运行,互操作性使用与上面相同的 Value
类。
有关运行 node
启动器和从 Java Context
访问 Node.js NPM 模块或 ECMAScript 模块之间的差异,请参阅 NodeJSVSJavaScriptContext。
使用 Node.js 进行多线程 #
GraalJS 的基本 多线程模型 也适用于 Node.js 应用程序。在 Node.js 中,可以创建 Worker 线程以并行执行 JavaScript 代码,但 JavaScript 对象不能在 Worker 之间共享。相反,使用 GraalVM Java 互操作性创建的 Java 对象(例如,使用 Java.type()
)可以在 Node.js Worker 之间共享。这允许多线程 Node.js 应用程序共享 Java 对象。
GraalVM Node.js 单元测试 包含一些多线程 Node.js 应用程序示例。最值得注意的示例展示了如何
- Node.js Worker 线程可以执行 Java 代码.
- Java 对象可以在 Node.js Worker 线程之间共享.
- 使用 Java 对象将 Promise 与 Worker 消息绑定,JavaScript
Promise
对象可用于对 Worker 消息进行await
.
常见问题解答 #
GraalVM 的 Node.js 运行时是否与原始 Node 实现兼容? #
GraalVM 的 Node.js 运行时与原始 Node.js(基于 V8 引擎)高度兼容。这导致大量基于 npm
的模块兼容。事实上,在我们测试的 10 万个 npm
模块中,超过 94% 的模块通过了所有测试。尽管如此,仍然需要考虑一些差异来源
-
设置:GraalVM 的 Node.js 大致模仿了 Node 的原始设置,包括
node
可执行文件、npm
以及类似的设置。但是,并非所有命令行选项都受支持(或行为完全相同)。模块可能需要针对 v8.h 文件(重新)编译原生模块。从适用于 JDK 21 的 GraalVM 开始,GraalVM Node.js 运行时作为单独的发布版提供。请参阅 Node.js 入门。
-
内部机制:GraalVM 的 Node.js 在 JVM 之上实现,因此具有与基于 V8 的 Node.js 不同的内部架构。这意味着某些内部机制的行为有所不同,不能完全复制 V8 的行为。这几乎不会影响用户代码,但可能会影响原生实现的模块,具体取决于 V8 内部机制。
-
性能:由于 GraalVM 的 Node.js 在 JVM 之上实现,因此性能特征与原始的原生实现有所不同。虽然 GraalVM 的峰值性能可以在许多基准测试中与 V8 相匹配,但通常需要更长的时间才能达到峰值(称为预热)。在测量(峰值)性能时,请务必为 Graal 编译器留出更多时间。
-
兼容性:GraalVM 的 Node.js 运行时使用以下方法来检查和保持与 Node.js 代码的兼容性
- node-compat-table:使用 node-compat-table 模块将 GraalVM 的 Node.js 与其他引擎进行比较,突出显示可能破坏 Node.js 代码的不兼容性。
- 使用 mocha 自动批量测试模块:为了测试大量模块,GraalVM 的 Node.js 运行时针对使用 mocha 测试框架的 9.5 万个模块进行了测试。使用 mocha 可以自动执行测试过程并理解测试结果。
- 手动测试流行模块:选择列表的
npm
模块将在手动测试设置中进行测试。这些高度相关的模块将在更复杂的测试环境中进行测试。
可以全局安装 NPM 包吗? #
可以使用 npm
和 -g
选项全局安装 Node 包,无论是 GraalVM 的 Node.js 实现还是原始的 Node.js 实现。
虽然原始的 Node.js 实现有一个主目录(node/bin/)来放置二进制文件和全局安装的包及其命令行工具,但 GraalVM 的 Node.js 将二进制文件放在 /path/to/graaljs/bin/ 目录中。在 GraalVM Node.js 运行时全局安装 NPM 包时,指向可执行文件的链接(例如,用于命令行界面工具的链接)将放在 JavaScript 特定的目录中。为了使全局安装的包正常工作,您可能需要将 /path/to/graaljs/bin
添加到 $PATH
中。
另一种方法是通过设置 $PREFIX
环境变量,或在运行 npm install
时指定 --prefix
选项,来指定 npm
的全局安装目录。
有关更多详细信息,请参阅 全局安装 npm
包。