nodejs/nan

Understanding Nan::AsyncResource

matteodisabatino opened this issue · 1 comments

Hi,
I'm trying to develop a node.js addon in C++ using nan in order to reproduce this behaviour:

console.log('MyModule: ', MyModule);

MyModule.on('data', (...args) => {
  console.log('on data args: ', args)
})

MyModule.on('data', (...args) => {
  console.log('on data 2 args: ', args)
})

MyModule.on('wrong-event', (...args) => {
  console.log('on wrong-event args: ', args)
})

If I write the addon this way:

#include <nan.h>

class GCAsyncResource : public Nan::AsyncResource
{
public:
	GCAsyncResource(v8::Local<v8::Function> callback_)
			: Nan::AsyncResource("event-callback")
	{
		callback.Reset(callback_);
	}

	~GCAsyncResource()
	{
		callback.Reset();
	}

	Nan::Persistent<v8::Function> callback;
};

static GCAsyncResource *gc_async_resource;

NAN_METHOD(on)
{
	if (info.Length() != 2)
	{
		return;
	}

	if (!info[0]->IsString())
	{
		return;
	}

	if (std::string(*Nan::Utf8String(info[0])) != "data")
	{
		return;
	}

	if (!info[1]->IsFunction())
	{
		return;
	}

	v8::Local<v8::Function> cb = Nan::To<v8::Function>(info[1]).ToLocalChecked();
	gc_async_resource = new GCAsyncResource(cb);

	v8::Local<v8::Value> cb_arguments[] = {
			Nan::New("hello world!!").ToLocalChecked()};

	v8::Local<v8::Function> callback = Nan::New(gc_async_resource->callback);
	v8::Local<v8::Object> target = Nan::New<v8::Object>();
	gc_async_resource->runInAsyncScope(target, callback, 1, cb_arguments);
}

NAN_MODULE_INIT(init)
{
	Nan::HandleScope scope;

	Nan::Set(target,
					 Nan::New("on").ToLocalChecked(),
					 Nan::GetFunction(
							 Nan::New<v8::FunctionTemplate>(on))
							 .ToLocalChecked());
}

NODE_MODULE(NODE_GYP_MODULE_NAME, init)

I receive this output: (the output it's correct since is exactly what I excpeted)

MyModule:  { on: [Function (anonymous)] }
on data args:  [ 'hello world!!' ]
on data 2 args:  [ 'hello world!!' ]

After, I've tried to extend my code in order to get data from garbage collection:

#include <nan.h>

class GCAsyncResource : public Nan::AsyncResource
{
public:
	GCAsyncResource(v8::Local<v8::Function> callback_)
			: Nan::AsyncResource("event-callback")
	{
		callback.Reset(callback_);
	}

	~GCAsyncResource()
	{
		callback.Reset();
	}

	Nan::Persistent<v8::Function> callback;
};

static GCAsyncResource *gc_async_resource;

NAN_GC_CALLBACK(onGCPrologue)
{
	// Things...
}

NAN_GC_CALLBACK(onGCEpilogue)
{
	// Things...
	v8::Local<v8::Value> cb_arguments[] = {
			Nan::New("hello world!!").ToLocalChecked()};

	v8::Local<v8::Function> callback = Nan::New(gc_async_resource->callback);
	v8::Local<v8::Object> target = Nan::New<v8::Object>();
	gc_async_resource->runInAsyncScope(target, callback, 1, cb_arguments);
}

NAN_METHOD(on)
{
	if (info.Length() != 2)
	{
		return;
	}

	if (!info[0]->IsString())
	{
		return;
	}

	if (std::string(*Nan::Utf8String(info[0])) != "data")
	{
		return;
	}

	if (!info[1]->IsFunction())
	{
		return;
	}

	v8::Local<v8::Function> cb = Nan::To<v8::Function>(info[1]).ToLocalChecked();
	gc_async_resource = new GCAsyncResource(cb);

	Nan::AddGCEpilogueCallback(onGCEpilogue);
}

NAN_MODULE_INIT(init)
{
	Nan::HandleScope scope;
	Nan::AddGCPrologueCallback(onGCPrologue);

	Nan::Set(target,
					 Nan::New("on").ToLocalChecked(),
					 Nan::GetFunction(
							 Nan::New<v8::FunctionTemplate>(on))
							 .ToLocalChecked());
}

NODE_MODULE(NODE_GYP_MODULE_NAME, init)

I expected to receive events in this case too, instead the only thing I can read on console is:

MyModule:  { on: [Function (anonymous)] }

I really don't know what am I wronging. May the problem stand on the class GCAsyncResource?

If it could be useful, I'm using:

  • node: v14.15.4
  • nan: v2.14.2
  • node-pre-gyp: v0.17.0

I solved my problem by own.