Skip to content

Node.js 与底层交互 (N-API / Wasm)

1. 集成方案选择

方案适用场景优点缺点
N-API (Native Addon)极致性能、系统级 API最高性能需要编译、平台相关
WebAssembly纯计算逻辑移植跨平台、安全不能调用系统 API
FFI (node-ffi-napi)快速调用动态库无需 C++ 胶水代码性能有损耗

2. N-API (Node-API) 🔥

解决的历史痛点

在 N-API 出现之前:

  • Native Addon 直接依赖 V8 API
  • Node.js 升级 → V8 版本变更 → API 变化 → 所有 Addon 重新编译/重写

ABI 稳定性

┌─────────────────────────────────────────────────────┐
│                   JavaScript                         │
├─────────────────────────────────────────────────────┤
│                     N-API                            │ ← 稳定的 C 抽象层
├─────────────────────────────────────────────────────┤
│     V8 (可能变化)      │    其他引擎 (未来可能)      │
└─────────────────────────────────────────────────────┘

IMPORTANT

使用 N-API 编写的插件,编译一次,多个 Node.js 主版本可用

基本示例

cpp
// addon.cc
#include <napi.h>

Napi::Value Add(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    
    double a = info[0].As<Napi::Number>().DoubleValue();
    double b = info[1].As<Napi::Number>().DoubleValue();
    
    return Napi::Number::New(env, a + b);
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
    exports.Set("add", Napi::Function::New(env, Add));
    return exports;
}

NODE_API_MODULE(addon, Init)
javascript
// 使用
const addon = require('./build/Release/addon');
console.log(addon.add(1, 2));  // 3

构建配置 (node-gyp)

python
# binding.gyp
{
    "targets": [{
        "target_name": "addon",
        "sources": ["addon.cc"],
        "include_dirs": [
            "<!@(node -p \"require('node-addon-api').include\")"
        ],
        "defines": ["NAPI_DISABLE_CPP_EXCEPTIONS"]
    }]
}

3. WebAssembly 🔥

适用场景

  • 纯计算逻辑 (加密、图像处理、算法)
  • 已有 C/C++/Rust 代码库移植
  • 需要浏览器和 Node.js 同时运行

基本使用

javascript
const fs = require('fs');

// 加载 Wasm 模块
const wasmBuffer = fs.readFileSync('./module.wasm');
const wasmModule = new WebAssembly.Module(wasmBuffer);
const wasmInstance = new WebAssembly.Instance(wasmModule);

// 调用导出函数
const result = wasmInstance.exports.add(1, 2);
console.log(result);

使用 AssemblyScript (TypeScript → Wasm)

typescript
// assembly/index.ts
export function fibonacci(n: i32): i32 {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}
bash
# 编译
npx asc assembly/index.ts -o build/module.wasm
javascript
// 使用
const loader = require('@assemblyscript/loader');
const wasm = await loader.instantiate(
    fs.readFileSync('./build/module.wasm')
);
console.log(wasm.exports.fibonacci(40));

性能对比

任务纯 JSWebAssembly提升
Fibonacci(40)1200ms300ms4x
图像模糊800ms200ms4x
MD5 哈希100ms20ms5x

4. FFI (Foreign Function Interface)

快速调用动态库

javascript
const ffi = require('ffi-napi');
const ref = require('ref-napi');

// 调用系统 C 库
const libm = ffi.Library('libm', {
    'ceil': ['double', ['double']],
    'floor': ['double', ['double']]
});

console.log(libm.ceil(1.5));   // 2
console.log(libm.floor(1.5));  // 1

适用场景

  • 快速原型验证
  • 调用已有的 .dll / .so 文件
  • 不想写 C++ 胶水代码

5. 实战场景举例

图片处理: Sharp

javascript
// Sharp 底层使用 libvips (C++),通过 N-API 暴露接口
const sharp = require('sharp');

await sharp('input.jpg')
    .resize(200, 200)
    .toFile('output.jpg');

// 性能比纯 JS 的 Jimp 快 10-100 倍

加密: bcrypt

javascript
// bcrypt 使用 C++ 实现
const bcrypt = require('bcrypt');
const hash = await bcrypt.hash('password', 10);

选型建议

前端面试知识库