Node.js 在 C/C++ 中添加模块
Node.js add on module in C/C++
我一直在探索在 C/C++ 中为 node.js 编写附加模块。到目前为止,我有一个简单的附加工作,我可以在其中调用附加函数形式 JavaScript,这非常简单。该例程称为 hello,它传递了一个字符串,然后 returns 相同的字符串,前缀为 Hello 和 space 两字之间。
package.json:
{
"name": "test",
"version": "2.0.0",
"description": "test description",
"main": "index.js",
"gypfile": true,
"scripts": {
"build": "node-gyp rebuild",
"clean": "node-gyp clean"
},
"author": "Simon Platten",
"license": "ISC",
"devDependencies": {
"node-gyp": "^7.1.2"
},
"dependencies": {
"node-addon-api": "^3.1.0"
}
}
binding.gyp:
{
"targets":[{
"target_name": "test",
"cflags!": ["-fno-exceptions"],
"cflags_cc!": ["-fno-exceptions"],
"sources": ["cpp/main.cpp"],
"include_dirs": ["<!@(node -p \"require('node-addon-api').include\")"],
"libraries": [],
"dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
"defines": ["NAPI_DISABLE_CPP_EXCEPTIONS"],
}]
}
main.cpp
/**
* File: main.cpp
* Notes:
* Work in progress for add on module for node.js 'test'
* History:
* 2021/03/11 Written by Simon Platten
*/
#include <napi.h>
#include <iostream>
#include <string>
/**
* Return "Hello " + user name passed back
*/
Napi::String hello(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
std::string strResult = "Hello ";
strResult += info[0].ToString();
return Napi::String::New(env, strResult);
}
/**
* Callback method when module is registered with Node.js
*/
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(
Napi::String::New(env, "hello"),
Napi::Function::New(env, hello)
);
return exports;
}
NODE_API_MODULE(test, Init);
index.js:
const test = require("./build/Release/test");
console.log(test.hello("Simon"));
效果很好,现在我想尝试一下。我不确定正确的术语,但是例如,当在节点中使用套接字时,有各种 on 回调或可以使用回调函数管理的事件.这正是我想从我的模块中实现的,该模块将传递大量数据进行处理,我将 return 在模块处理数据并完成并为客户端准备好时立即我想以 on 样式处理程序的形式向 node.js 发出通知。
如何?
在 JS 中:
创建一个继承自 EventEmitter 的 class。这样做你将能够从这个 class.
中收听事件
如果您使用此 class 的回调调用您的插件函数,并在回调中发出您的事件,您可以实现您想要的。
像这样:
const test = require("./build/Release/test");
const EventEmitter = require('events');
class Test extends EventEmitter {
constructor() {
super();
this.addon = test;
}
test() {
test.hello("Simon", (data) => {
this.emit("testEvent", data);
});
}
}
const myTest = new Test();
myTest.on("testEvent", (data) => {
console.log("testEvent says: ", data);
})
myTest.test();
在 C++ 中:
根据找到的示例 here,您可以添加一个 AsyncWorker,它将在后台处理您的数据并在完成后调用回调。
像这样:
#include <napi.h>
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
using namespace Napi;
class TestWorker : public AsyncWorker {
public:
TestWorker(Function& callback) : AsyncWorker(callback) {}
void Execute() override {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
void OnOK() override {
HandleScope scope(Env());
Callback().Call({String::New(Env(), "message from the addon")});
}
};
您可以将此回调作为参数提供给您的 hello 函数以及您当前的参数“Simon”。
您的代码使用回调参数和 AsyncWorker 的启动进行了扩展:
Napi::String hello(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
std::string strResult = "Hello ";
strResult += info[0].ToString();
Function cb = info[1].As<Function>();
TestWorker* wk = new TestWorker(cb);
wk->Queue();
return Napi::String::New(env, strResult);
}
如果您打算在使用事件发射器概念的同时创建流,那么您可能会发现这个 post 很有趣
如果您需要以不阻塞异步操作的方式执行此操作,那么您可以在单独的线程上执行此操作,因为您必须使用 napi_threadsafe_function。用法有点复杂,在Whosebug中有详细解释 post
我一直在探索在 C/C++ 中为 node.js 编写附加模块。到目前为止,我有一个简单的附加工作,我可以在其中调用附加函数形式 JavaScript,这非常简单。该例程称为 hello,它传递了一个字符串,然后 returns 相同的字符串,前缀为 Hello 和 space 两字之间。
package.json:
{
"name": "test",
"version": "2.0.0",
"description": "test description",
"main": "index.js",
"gypfile": true,
"scripts": {
"build": "node-gyp rebuild",
"clean": "node-gyp clean"
},
"author": "Simon Platten",
"license": "ISC",
"devDependencies": {
"node-gyp": "^7.1.2"
},
"dependencies": {
"node-addon-api": "^3.1.0"
}
}
binding.gyp:
{
"targets":[{
"target_name": "test",
"cflags!": ["-fno-exceptions"],
"cflags_cc!": ["-fno-exceptions"],
"sources": ["cpp/main.cpp"],
"include_dirs": ["<!@(node -p \"require('node-addon-api').include\")"],
"libraries": [],
"dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
"defines": ["NAPI_DISABLE_CPP_EXCEPTIONS"],
}]
}
main.cpp
/**
* File: main.cpp
* Notes:
* Work in progress for add on module for node.js 'test'
* History:
* 2021/03/11 Written by Simon Platten
*/
#include <napi.h>
#include <iostream>
#include <string>
/**
* Return "Hello " + user name passed back
*/
Napi::String hello(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
std::string strResult = "Hello ";
strResult += info[0].ToString();
return Napi::String::New(env, strResult);
}
/**
* Callback method when module is registered with Node.js
*/
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(
Napi::String::New(env, "hello"),
Napi::Function::New(env, hello)
);
return exports;
}
NODE_API_MODULE(test, Init);
index.js:
const test = require("./build/Release/test");
console.log(test.hello("Simon"));
效果很好,现在我想尝试一下。我不确定正确的术语,但是例如,当在节点中使用套接字时,有各种 on 回调或可以使用回调函数管理的事件.这正是我想从我的模块中实现的,该模块将传递大量数据进行处理,我将 return 在模块处理数据并完成并为客户端准备好时立即我想以 on 样式处理程序的形式向 node.js 发出通知。
如何?
在 JS 中:
创建一个继承自 EventEmitter 的 class。这样做你将能够从这个 class.
中收听事件如果您使用此 class 的回调调用您的插件函数,并在回调中发出您的事件,您可以实现您想要的。
像这样:
const test = require("./build/Release/test");
const EventEmitter = require('events');
class Test extends EventEmitter {
constructor() {
super();
this.addon = test;
}
test() {
test.hello("Simon", (data) => {
this.emit("testEvent", data);
});
}
}
const myTest = new Test();
myTest.on("testEvent", (data) => {
console.log("testEvent says: ", data);
})
myTest.test();
在 C++ 中:
根据找到的示例 here,您可以添加一个 AsyncWorker,它将在后台处理您的数据并在完成后调用回调。
像这样:
#include <napi.h>
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
using namespace Napi;
class TestWorker : public AsyncWorker {
public:
TestWorker(Function& callback) : AsyncWorker(callback) {}
void Execute() override {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
void OnOK() override {
HandleScope scope(Env());
Callback().Call({String::New(Env(), "message from the addon")});
}
};
您可以将此回调作为参数提供给您的 hello 函数以及您当前的参数“Simon”。
您的代码使用回调参数和 AsyncWorker 的启动进行了扩展:
Napi::String hello(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
std::string strResult = "Hello ";
strResult += info[0].ToString();
Function cb = info[1].As<Function>();
TestWorker* wk = new TestWorker(cb);
wk->Queue();
return Napi::String::New(env, strResult);
}
如果您打算在使用事件发射器概念的同时创建流,那么您可能会发现这个 post 很有趣
如果您需要以不阻塞异步操作的方式执行此操作,那么您可以在单独的线程上执行此操作,因为您必须使用 napi_threadsafe_function。用法有点复杂,在Whosebug中有详细解释 post