Node.js是如何识别读取C++代码的?二者的通信机制是什么?
Node.js 与 C++ 交互核心原理说明
基础前提
Node.js 本身就是基于 C++ 编写的 V8 引擎、libuv 异步IO库等原生组件构建的 runtime,天生具备和 C++ 交互的底层能力,不需要额外做适配。
Node.js 调用 C++ 代码的逻辑
首先明确:Node.js 无法直接识别、读取原始的 C++ 源代码,C++ 代码必须提前编译为符合规范的二进制动态链接库,才能被 Node.js 加载调用,主流的两种实现路径如下:
- 官方标准扩展方案:基于 Node 官方维护的跨版本稳定接口 Node-API(旧称 N-API) 编写 C++ 扩展代码,在代码中按照规范导出可供 JS 调用的方法,之后使用
node-gyp构建工具将 C++ 代码编译为后缀为.node的二进制文件,Node.js 可以直接通过require()导入该二进制文件,使用体验和导入普通 JS 模块没有明显差异。 - 轻量对接方案:如果是对接已有的 C++ 库,不需要额外写 Node 扩展,可以使用
ffi-napi这类封装好的库,直接加载通用 C++ 动态库(Windows 下为.dll、Linux 下为.so、Mac 下为.dylib),只需要在 JS 侧声明对应 C++ 函数的入参、返回值类型,即可直接调用。
二者通信的实现机制
两者的通信核心依赖 V8 引擎的类型桥接能力和 Node 的异步调度能力:
- 类型转换:JS 是动态类型语言,C++ 是静态类型语言,所有跨语言调用的入参、返回值都需要经过 V8 做类型映射,比如 JS 的
Number会转为 C++ 的int/double类型,JS 的ArrayBuffer可以直接映射到 C++ 侧的内存指针,实现零拷贝数据传输。 - 调用栈切换:JS 侧调用 C++ 方法时,V8 会暂时暂停 JS 虚拟机的执行,把执行权交给原生代码层,C++ 逻辑执行完成后,会把结果转为 V8 可识别的标准类型,再把执行权交回 JS 执行栈。
- 异步通信处理:如果 C++ 侧有耗时操作,为了不阻塞 JS 主线程,会通过 libuv 的线程池把 C++ 任务丢到后台线程执行,执行完成后再通过 Node 的事件循环把回调结果抛回 JS 主线程,完全符合 JS 的异步编程习惯。
极简示例
C++ 扩展核心代码:
napi_value Add(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; // 获取JS侧传入的参数 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); double val1, val2; // 把JS的Number转为C++的double napi_get_value_double(env, args[0], &val1); napi_get_value_double(env, args[1], &val2); napi_value res; // 把计算结果转回JS的Number napi_create_double(env, val1 + val2, &res); return res; }
JS 侧调用代码:
// 直接导入编译好的.node二进制文件 const addon = require('./build/Release/addon.node'); console.log(addon.Add(2, 3)); // 输出 5
内容的提问来源于stack exchange,提问作者Chetan
相关产品推荐
相关产品推荐

