【问题标题】:Node.js add on module in C/C++Node.js 在 C/C++ 中添加模块
【发布时间】:2021-03-11 14:10:00
【问题描述】:

我一直在探索用 C/C++ 为 node.js 编写附加模块。到目前为止,我有一个简单的附加工作,我可以在 JavaScript 中调用附加功能,这非常简单。该例程称为 hello,它传递一个字符串,然后返回以 Hello 为前缀的相同字符串,两个单词之间有一个空格。

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"],
    }]
}

ma​​in.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 回调或可以使用回调函数管理的事件。这正是我想从我的模块中实现的,模块将传递大量数据进行处理,当模块处理数据时,我将立即返回,并且当它完成并准备好用于我要发布的客户端时以 on 样式处理程序的形式向 node.js 发送通知。

怎么做?

【问题讨论】:

    标签: c++ node.js node.js-addon


    【解决方案1】:

    在 JS 中:

    创建一个继承自EventEmitter 的类。这样做你就可以收听这个类的事件了。

    如果您使用此类的回调调用插件的函数,并在回调中发出事件,您可以实现您想要的。

    类似这样的:

    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);
     }
    

    【讨论】:

      【解决方案2】:

      如果您打算在使用事件发射器概念的同时创建流式传输,那么您可能会发现这篇文章很有趣Streaming data into a Node.js C++ Addon with N-API

      如果您需要在没有阻塞异步操作的情况下执行此操作,那么您可以在单独的线程上执行此操作,因为您必须使用 napi_threadsafe_function。用法有点复杂,在 StackOverflow 帖子How to use napi_threadsafe_function for NodeJS Native Addon中有详细说明

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-04
        • 2016-03-24
        • 2017-09-23
        • 2012-09-09
        • 1970-01-01
        • 2018-10-23
        • 1970-01-01
        • 2014-02-11
        相关资源
        最近更新 更多