node-addon-api icon indicating copy to clipboard operation
node-addon-api copied to clipboard

AsyncWorker pass Napi::Object problem?

Open tak40548798 opened this issue 1 year ago • 1 comments

I want to pass in the object as a parameter

I get error

"Fatal error in HandleScope::HandleScope" "Entering the V8 API without proper locking in place"

example


class TestWorker : public Napi::AsyncWorker {
 public:
  TestWorker(Napi::Function& callback, Napi::Object& object)
      : Napi::AsyncWorker(callback), object(object) {}
  ~TestWorker() {}

  void Execute() {
    Napi::TypedArray typedArray = object.Get("data").As<Napi::TypedArray>();
    Napi::Uint8Array uint8Array = typedArray.As<Napi::Uint8Array>();
    std::vector<uchar> vector(uint8Array.Data(), uint8Array.Data() + uint8Array.ElementLength());
    // vector data send to other function calculator

    uint32_t width = object.Get("width").As<Napi::Number>().Uint32Value();
    uint32_t height = object.Get("height").As<Napi::Number>().Uint32Value();
    size = width * height;

    result.Set("size", size);

    std::cout << size << std::endl;
  }

  void OnOK() { Callback().Call({Env().Undefined(), result}); }

  Napi::Object object;
  Napi::Object result = Napi::Object::New(Env());
  uint32_t size;
};

Napi::Value TestAsync(const Napi::CallbackInfo& info) {
  Napi::Object object = info[0].As<Napi::Object>();
  Napi::Function callback = info[1].As<Napi::Function>();

  TestWorker* testWorker = new TestWorker(callback, object);
  testWorker->Queue();

  return info.Env().Undefined();
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
  exports.Set(Napi::String::New(env, "testAsync"),Napi::Function::New(env, TestAsync));
  return exports;
}
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
const object = { data: new Uint8Array([1, 2, 3, 4, 5, 6]), width: 123, height: 456 };

addon.testAsync(object, (err, result) => {
  console.log(result);
});
/*
Error message
# Fatal error in HandleScope::HandleScope
# Entering the V8 API without proper locking in place
*/

tak40548798 avatar Oct 14 '22 08:10 tak40548798

Hi @tak40548798 ,

Please check the documentation for the Execute callback, specifically:

As the method is not running on the main event loop, it must avoid calling any methods from node-addon-api or running any code that might invoke JavaScript. Instead, once this method is complete any interaction through node-addon-api with JavaScript should be implemented in the Napi::AsyncWorker::OnOK method and Napi::AsyncWorker::OnError which run on the main thread and are invoked when the Napi::AsyncWorker::Execute method completes.

You cannot execute JavaScript code in the Execute callback.

Let us know if you need any additional assistance.

Thanks, Kevin

KevinEady avatar Oct 14 '22 08:10 KevinEady

Hi @tak40548798, @KevinEady is right you cannot execute JavaScript code in the Execute method so one idea is to refactor your code like reported below:

#include <napi.h>

class TestWorker : public Napi::AsyncWorker {
 public:
  TestWorker(Napi::Function& callback, Napi::Object& object)
      : Napi::AsyncWorker(callback) {
        Napi::TypedArray typedArray = object.Get("data").As<Napi::TypedArray>();
        Napi::Uint8Array uint8Array = typedArray.As<Napi::Uint8Array>();
        vector = std::vector<char>(uint8Array.Data(), uint8Array.Data() + uint8Array.ElementLength());
        // vector data send to other function calculator
        width = object.Get("width").As<Napi::Number>().Uint32Value();
        height = object.Get("height").As<Napi::Number>().Uint32Value();


      }
  ~TestWorker() {}

  void Execute() { 
    result = width * height;
  }

  void OnOK() { 
    Napi::Object obj = Napi::Object::New(Env());
    obj["size"] = result;
    Callback().Call({Env().Undefined(), obj}); 
  }

  std::vector<char> vector;
  uint32_t width;
  uint32_t height;
  uint32_t result;
  
};

Napi::Value TestAsync(const Napi::CallbackInfo& info) {
  Napi::Object object = info[0].As<Napi::Object>();
  Napi::Function callback = info[1].As<Napi::Function>();

  TestWorker* testWorker = new TestWorker(callback, object);
  testWorker->Queue();

  return info.Env().Undefined();
}

Napi::Object Init(Napi::Env env, Napi::Object exports) {
  exports.Set(Napi::String::New(env, "testAsync"),Napi::Function::New(env, TestAsync));
  return exports;
}
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
'use strict'

const addon = require('bindings')('addon')

const object = { data: new Uint8Array([1, 2, 3, 4, 5, 6]), width: 123, height: 456 };

addon.testAsync(object, (err, result) => {
  console.log(result);
});

Let us know if this help you or need some other assistance.

NickNaso avatar Nov 03 '22 18:11 NickNaso

Is is possible to return an ObjectWrap as the result of a Promise? Seems impossible given CallbackInfo isn't accessible within OnOK().

jklontz avatar Dec 12 '22 22:12 jklontz

This issue is stale because it has been open many days with no activity. It will be closed soon unless the stale label is removed or a comment is made.

github-actions[bot] avatar Mar 13 '23 00:03 github-actions[bot]