До сих пор я реализовывал только синхронные методы node-addon-api, т. Е. Функция JavaScript выполняет вызов, работа завершена, а дополнение возвращается. У меня большие пробелы в знаниях, когда дело доходит до внутренней работы v8, libuv и node, поэтому, пожалуйста, исправьте любые очевидные заблуждения.
Цель состоит в том, чтобы вызвать JavaScript обратный вызов, когда обратные вызовы сборки мусора C ++ звонил с v8. Изначально я только что вызвал обратный вызов JavaScript из обратного вызова сборки мусора v8, но после пары звонков это закончилось segv. Кажется, что просто вызов в JavaScript при вызове из обратного вызова v8 имеет некоторые проблемы (v8 документирует, что обратные вызовы не должны выделять объекты). Поэтому я оглянулся и нашел пример на основе Nan, который использует libuv
и Nan AsyncResource
для выполнения обратного вызова. Следующий подход работает с использованием node-nan
:
NAN_GC_CALLBACK(afterGC) {
uint64_t et = uv_hrtime() - gcStartTime;
// other bookkeeping for GCData_t raw.
if (doCallbacks) {
uv_async_t* async = new uv_async_t;
GCData_t* data = new GCData_t;
*data = raw;
data->gcTime = et;
async->data = data;
uv_async_init(uv_default_loop(), async, asyncCB);
uv_async_send(async);
}
}
class GCResponseResource : public Nan::AsyncResource {
public:
GCResponseResource(Local<Function> callback_)
: Nan::AsyncResource("nan:gcstats.DeferredCallback") {
callback.Reset(callback_);
}
~GCResponseResource() {
callback.Reset();
}
Nan::Persistent<Function> callback;
};
static GCResponseResource* asyncResource;
static void closeCB(uv_handle_t *handle) {
delete handle;
}
static void asyncCB(uv_async_t *handle) {
Nan::HandleScope scope;
GCData_t* data = static_cast<GCData_t*>(handle->data);
Local<Object> obj = Nan::New<Object>();
Nan::Set(obj, Nan::New("gcCount").ToLocalChecked(),
Nan::New<Number>((data->gcCount));
Nan::Set(obj, Nan::New("gcTime").ToLocalChecked(),
Nan::New<Number>(data->gcTime));
Local<Object> counts = Nan::New<v8::Object>();
for (int i = 0; i < maxTypeCount; i++) {
if (data->typeCounts[i] != 0) {
Nan::Set(counts, i, Nan::New<Number>(data->typeCounts[i]));
}
}
Nan::Set(obj, Nan::New("gcTypeCounts").ToLocalChecked(), counts);
Local<Value> arguments[] = {obj};
Local<Function> callback = Nan::New(asyncResource->callback);
v8::Local<v8::Object> target = Nan::New<v8::Object>();
asyncResource->runInAsyncScope(target, callback, 1, arguments);
delete data;
uv_close((uv_handle_t*) handle, closeCB);
}
Мой вопрос заключается в том, как бы я сделал это, используя node-addon-api вместо nan?
Мне не ясно, что node-addon-api эквивалентный uv_async_init
, uv_async_send
, et c are. Это отчасти потому, что мне не ясно, какие базовые функции N-API
(в отличие от node-addon-api
) требуются.
Мне не удалось найти пример, подобный этому. Пример обратного вызова является полностью синхронным. asyn c pi пример использует рабочий поток для выполнения задачи, но это кажется излишним по сравнению с подходом в коде на основе nan, использующим примитивы uv
.