On the problem of calling each other between Node and CPP

recently read a lot of related documents; but there is one place that has been puzzled. About Node calling the CPP callback function:
the official documents are as follows:

CPP section:

// addon.cc
-sharpinclude <node.h>

namespace demo {

using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Null;
using v8::Object;
using v8::String;
using v8::Value;

void RunCallback(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  Local<Function> cb = Local<Function>::Cast(args[0]);
  const unsigned argc = 1;
  Local<Value> argv[argc] = { String::NewFromUtf8(isolate, "hello world") };
  cb->Call(Null(isolate), argc, argv);
}

void Init(Local<Object> exports, Local<Object> module) {
  NODE_SET_METHOD(module, "exports", RunCallback);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Init)

}  // namespace demo

js

// test.js
const addon = require("./build/Release/addon");

addon((msg) => {
  console.log(msg);
// Prints: "hello world"
});

you can see that although the js in this demo is function, it is executed by Synchronize in the CPP module; and if Synchronize executes, I have also called it, but the actual scenario is definitely not this kind of requirement. Instead, it is called back to js; through the callback function passed by the js module through the callback function passed by the js module after receiving a certain message in an asynchronous event monitor of the js module.

what has been done so far:
encapsulates a CPP class, and export, can call instance methods of this class with js;

two attributes of the .h file:

Isolate *onPlayNoteIsolate;
Local <Function> onPlayNote;

.cpp file

// 1:
void MIDIDeviceHelperBridge::setOnPlayNote(const FunctionCallbackInfo<Value>& args) {
    MIDIDeviceHelperBridge *obj = ObjectWrap::Unwrap<MIDIDeviceHelperBridge>(args.Holder());
    
    Local<Function> callback = Local<Function>::Cast(args[1]);
    obj->onPlayNote = callback;
    obj->onPlayNoteIsolate = args.GetIsolate();
}

// 2:
void MIDIDeviceHelperBridge::ReceiveMsg(DWORD Msg, DWORD TimeStamp) {
    // this1obj
}

my requirement now is that the callback function of the js module obtained in method 1 is stored in obj or wherever the CPP module can access, and then after receiving the message in method 2, the message is passed to the js module through the callback of the js module obtained by method 1;

I tried to store callback and isolate, in obj in method 1, and then access callback and isolate, through this in method 2, but after receiving the message, the program crashed. I found that there was no problem with isolate, but callback was released. Later, I also tried to change the Local < Function > onPlayNote;
type to Persistent < Function > onPlayNote; and Handle < Function > onPlayNote; also crashed after receiving the message.

now I would like to ask if there are any great gods who have done similar functions.

=
modify part of the problem after a few hours:

1:Persistent <Function> onPlayNote;Persistent;
2:ReceiveMsgjsjsjs;
3:ReceiveMsgMIDIUSBwindowsmidiapiReceiveMsgReceiveMsgjs;

=

Mar.25,2021

also encountered the same problem. Now I just give up cPP


.

resolved
received messages are stored in the message queue of the current object and then sent to the js module via emit:

CPP part

// Newrunloop
void MIDIDeviceHelperBridge::New(const FunctionCallbackInfo<Value>& args) {
    MIDIDeviceHelperBridge *obj = new MIDIDeviceHelperBridge();
    obj->isolate = isolate;
    obj->message_async.data = obj;
    uv_async_init(uv_default_loop(), &obj->message_async, MIDIDeviceHelperBridge::MIDIMessageCallback);
    
}

void MIDIDeviceHelperBridge::ReceiveMsg(DWORD Msg, DWORD TimeStamp) {
    uv_async_send(&this->message_async);
}

void MIDIDeviceHelperBridge::MIDIMessageCallback(uv_async_t *async) {
    MIDIDeviceHelperBridge *obj = static_cast<MIDIDeviceHelperBridge*>(async->data);
    Local<v8::Function> emitFunction = obj->handle()->Get(String::NewFromUtf8(obj->isolate, "emit")).As<v8::Function>();
    const unsigned argc = 4;
    char *CustomMessageName = "CustomMessageName";
    Local <Value> argv[argc] = {
        String::NewFromUtf8(obj->isolate, CustomMessageName),
        Number::New(obj->isolate, 1),
        Number::New(obj->isolate, 2),
        Number::New(obj->isolate, 3)
    };
    MakeCallback(obj->isolate, obj->handle(), emitFunction, argc, argv);
}

js section:

const midiDeviceHelper = require(`xxx.node`);//
const EventEmitter = require('events').EventEmitter;
midiDeviceHelper.MIDIDeviceHelperBridge.prototype.__proto__ = EventEmitter.prototype;
const midiDeviceHelperBridge = new midiDeviceHelper.MIDIDeviceHelperBridge();
const CustomMessageName = "CustomMessageName"; //argv
midiDeviceHelperBridge.on(CustomMessageName, (a, b, c) => {
});

how is the handle () method of the MIDIDeviceHelperBridge class implemented?
an example of kneeling for completeness? @ kingphone_he

MySQL Query : SELECT * FROM `codeshelper`.`v9_news` WHERE status=99 AND catid='6' ORDER BY rand() LIMIT 5
MySQL Error : Disk full (/tmp/#sql-temptable-64f5-1ea8281-1eb7.MAI); waiting for someone to free some space... (errno: 28 "No space left on device")
MySQL Errno : 1021
Message : Disk full (/tmp/#sql-temptable-64f5-1ea8281-1eb7.MAI); waiting for someone to free some space... (errno: 28 "No space left on device")
Need Help?