Nodejs C++插件(N-API)
Nodejs C++插件(N-API)
N-API 作为Nodejs项目的一部分,旨在更加便捷稳定的创建Nodejs Native 插件。这个API作为应用二进制接口(ABI),在Node.js的各个版本中都是稳定的,而且ABI允许一个在主要版本编译的模块,在以后的Node.js版本上运行,而无需重新编译。
0. 环境搭建
- 安装最新的npm,且Nodejs版本10.x以上
- 工具链
- Windows执行
npm install --global windows-build-tools - MacOS执行
xcode-select --install - Linux使用系统自带的GCC即可
- Windows执行
- 安装构建工具
npm install --global node-gyp - 初始化测试项目
npm init - 添加napi模块
npm i node-addon-api - 为VSCode添加智能提示所需头文件(以Windows为例)
Ctrl+Shift+P-> C++ 添加c_cpp_properties.json文件执行
node-gyp configure查看-Dnode_root_dir选项打印,确认node头文件目录

c_cpp_properties.jsonincludePath 中加入C:\\Users\\gaobowen\\AppData\\Local\\node-gyp\\Cache\\10.16.0\\include\\node
1. JS中调用C++方法
1.1 JS中调用源文件的C++方法
- 编写功能函数
test.h、test.cc
#ifndef SAMPLE_TEST_H
#define SAMPLE_TEST_H
#include <napi.h>
#include <windows.h>
#include <sstream>
#include <thread>
Napi::Value plus(const Napi::CallbackInfo& info);
#endif
#include "test.h"
Napi::Value plus(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::EscapableHandleScope scope(env);
if (info.Length() < 1)
return Napi::Boolean::New(env, false);
if (!info[0].IsNumber())
return Napi::Boolean::New(env, false);
if (!info[1].IsNumber())
return Napi::Boolean::New(env, false);
auto a = info[0].As<Napi::Number>().DoubleValue();
auto b = info[1].As<Napi::Number>().DoubleValue();
return Napi::Number::New(env, a + b);
}
- 编写导出函数
exports.cc
#include <napi.h>
#include "test.h"
Napi::Object Init(Napi::Env env, Napi::Object exports)
{
exports.Set(Napi::String::New(env, "plus"), Napi::Function::New(env, plus));
return exports;
}
NODE_API_MODULE(napi_sample, Init)
- 添加
binding.gyp文件
{
"targets": [
{
"target_name": "napi_sample",
"sources": [ ],
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ],
"defines": [ "NAPI_DISABLE_CPP_EXCEPTIONS" ],
"include_dirs": [
"<!--@(node -p \"require('node-addon-api').include\")"
],
"conditions": [
['OS=="win"', {
"sources": [ "sample/exports.cc", "sample/test.cc" ],
}]
]
}
]
}
- 命令行执行
node-gyp rebuild生成./build/Release/napi_sample.node文件 - 测试使用
napi_sample.node插件
node .\test.js
let { plus } = require('./build/Release/napi_sample.node');
console.log('test export=-->', plus);
console.log('test call=>', plus(1.2, 1.3));
控制台输出
test export=> function () { [native code] }
test call=> 2.5
1.2 JS中调用动态库的C++方法
Napi::Value call_dll(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::EscapableHandleScope scope(env);
//注,若动态库还有其他依赖库,请放在同一级目录下
auto m = LoadLibraryExA("user32.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
typedef int(*MyMessageBoxA)(int, char*, char*, int);
auto box = (MyMessageBoxA)GetProcAddress(m, "MessageBoxA");
box(0, "js call dll function", "abc", 0);
return Napi::Boolean::New(env, true);
}
控制台输出
test call_dll=> true

2. C++中调用JS方法
2.1. C++单线程调用JS方法
test.cpp
Napi::Value cpp_call_js(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::EscapableHandleScope scope(env);
if (info.Length() < 0)
return Napi::Boolean::New(env, false);
if (!info[0].IsFunction())
return Napi::Boolean::New(env, false);
auto jscb = info[0].As<napi::function>();
//回调函数入参
napi_value a, b;
napi_create_double(env, 1, &a);
napi_create_double(env, 2, &b);
napi_value argv[] = { a, b };
//回调函数返回值
napi_value result;
napi_call_function(env, env.Global(), jscb, 2, argv, &result);
return Napi::Value(env, result);
}
test.js
let { cpp_call_js } = require('./build/Release/napi_sample.node');
(async function () {
let c = 3;
let js_callback = function(a, b){
return a + b + c;
}
console.log('test cpp_call_js=>', cpp_call_js(js_callback));
})();
控制台输出
test cpp_call_js=> 6
2.2. C++多线程调用JS方法
test.cpp
Napi::ThreadSafeFunction tsfunc;
void thread_function() {
auto threadid = std::this_thread::get_id();
std::stringstream ss;
ss << threadid;
auto threadidstr = new std::string(ss.str());
auto callback = [threadid](Napi::Env env, Napi::Function jscb, std::string* p_str) {
jscb.Call({ Napi::String::New(env, *p_str) });
delete p_str;
};
tsfunc.Acquire();
napi_status status = tsfunc.BlockingCall(threadidstr, callback);
if (status != napi_ok) {
printf("tsfunc.BlockingCall error.\n");
}
tsfunc.Release();
}
Napi::Value cpp_thread_call_js(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
Napi::EscapableHandleScope scope(env);
if (info.Length() < 0)
return Napi::Boolean::New(env, false);
if (!info[0].IsFunction())
return Napi::Boolean::New(env, false);
auto jscb = info[0].As<napi::function>();
tsfunc = Napi::ThreadSafeFunction::New(env, jscb, "my-tsfunc", 2, 2);
std::thread(thread_function).join();
std::thread(thread_function).join();
return Napi::Boolean::New(env, true);
}
test.js
let { cpp_thread_call_js } = require('./build/Release/napi_sample.node');
(async function () {
let js_callback_async = function(id){
console.log('thread_id',id);
}
console.log('test cpp_thread_call_js=>', cpp_thread_call_js(js_callback_async));
})();
控制台输出
test cpp_thread_call_js=> true
thread_id 6768
thread_id 12352
Nodejs C++插件(N-API)的更多相关文章
- Linux中安装nodejs及插件
Linux中安装nodejs及插件 1.去官网下载安装包 英文网址:https://nodejs.org/en/download/ 中文网址:http://nodejs.cn/download/ 通过 ...
- 教你如何通过CodeArts IDE插件调用API,高效合成语音
摘要:本实验基于华为云自研CodeArts IDE,指导用户通过使用华为云API,来实现一个文字合成语音的应用. 本文分享自华为云社区<通过CodeArts IDE插件调用API,高效合成语音! ...
- NodeJS学习三之API
Node采用V8引擎处理JavaScript脚本,最大特点就是单线程运行,一次只能运行一个任务.这导致Node大量采用异步操作(asynchronous opertion),即任务不是马上执行,而是插 ...
- sublime text 安装nodejs开发插件
系统:windows10nodejs版本:v6.1.14 请先配置好环境变量,这里就不说啦. 下载并设置nodejs插件 下载地址为https://github.com/tanepiper/Subli ...
- nodejs 各种插件
__dirname:全局变量,存储的是文件所在的文件目录 __filename:全局变量,存储的是文件名 代码:dirname.jsconsole.log(__dirname); 运行node dir ...
- FullCalendar日历插件(中文API)
FullCalendar提供了丰富的属性设置和方法调用,开发者可以根据FullCalendar提供的API快速完成一个日历日程的开发,本文将FullCalendar的常用属性和方法.回调函数等整理成中 ...
- PhpStorm插件之Api Debugger
安装插件 File->Setting->Pluugins 搜索 Api Debugger 如何使用 安装完插件后,RESTART IDE,在编辑器右侧 即可找到最新安装的 Api D ...
- Elasticsearch--集群管理_别名&插件&更新API
目录 使用索引别名 别名 创建别名 修改别名 合并命令 获取所有别名 移除别名 别名中过滤 别名和路由 Elasticsearch插件 基础知识 安装插件 移除插件 更新设置API 使用索引别名 通过 ...
- 【Azure 应用服务】NodeJS Express + MSAL 实现API应用Token认证(AAD OAuth2 idToken)的认证实验 -- passport.authenticate('oauth-bearer', {session: false})
问题描述 在前两篇博文中,对NodeJS Express应用 使用MSAL + AAD实现用户登录并获取用户信息,获取Authorization信息 ( ID Token, Access Token) ...
- 笔记-Nodejs中的核心API之Events
最近正在学习Node,在图书馆借了基本关于Node的书,同时在网上查阅资料,颇有收获,但是整体感觉对Node的理解还是停留在一个很模棱两可的状态.比如Node中的模块,平时练习就接触到那么几个,其他的 ...
随机推荐
- 痞子衡嵌入式:MCUXpresso IDE下在线联合调试i.MXRT1170双核工程的三种方法
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是MCUXpresso IDE下在线联合调试i.MXRT1170双核工程的三种方法. 两年前痞子衡写过一篇<i.MXRT1170下在 ...
- RHCA rh442 003 系统资源 查看硬件 tuned调优
监控工具 zabbix 监控具体业务,列如数据库.触发式事件(断网 硬盘坏一个) 普罗米修斯 给容器做监控 管理人员,如何知道几千台服务器哪些出了问题,这得需要zabbix 系统硬件资源 cpu [r ...
- 图解Java设计模式
待补充 设计模式介绍 设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案. 设计模式使用的位置 功能模块+框架上. 设计模式在软件中哪里?面向对象( ...
- 程序员学习网站推荐:路线向导(roadmap.sh)
网站地址: https://roadmap.sh/ 在外网的技术论坛上看到这个网站,上面给出多种编程语言的学习路线,也就是给出不同编程语言的从易到难的组成内容(语言特性),通过这个网站可以辅助学习编程 ...
- 如何在CMAKE中指定python路径——使用cmake为python编译扩展模块时指定python路径
答案: cmake -DPython3_EXECUTABLE=/path/to/bin/python3 ================================================ ...
- UITableView的原理——探究及重新实现代码
转自简书,原文地址,本文主要探讨一些特殊细节,像视图重用这类最基本的原理可在源码里查看. 先前重新实现了一个list容器视图,由于Apple没有开源,在此分享过程中探索到的UITableView一些细 ...
- 【Spring源码分析】Spring Scope功能中的动态代理 - Scoped Proxy
本文基于Springboot 3.3.2及Springcloud 2023.0.1版本编写. Spring Scoped Proxy是什么 在使用Spring cloud配置中心动态配置更新功能时,笔 ...
- UDP协议实现音频传输
目录 服务器端 客户端 服务器端 /********************************************************************************** ...
- 【Azure Developer】使用Python SDK去Azure Container Instance服务的Execute命令的疑问解释
Azure Container Instance服务介绍 Azure 容器实例(Azure Container Instances,简称 ACI)是一个无服务器容器解决方案,允许用户在 Azure 云 ...
- C语言操作时间函数time.ctime,实现定时执行某个任务小例子
时间操作函数在实际项目开发中会经常用到,最近做项目也正好用到就正好顺便整理一下. 时间概述 由上图可知: 通过系统调用函数time()可以从内核获得一个类型为time_t的1个值,该值叫calenda ...