Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AsyncWorker pass Napi::Object problem? #1221

Closed
samhuang1111 opened this issue Oct 14, 2022 · 4 comments
Closed

AsyncWorker pass Napi::Object problem? #1221

samhuang1111 opened this issue Oct 14, 2022 · 4 comments
Labels

Comments

@samhuang1111
Copy link

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
*/
@KevinEady
Copy link
Contributor

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

@NickNaso
Copy link
Member

NickNaso commented Nov 3, 2022

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.

@jklontz
Copy link

jklontz commented Dec 12, 2022

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

@github-actions
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants