Skip to content

ThreadSafeFunction : The exception is threw in CPP, but not JS. #669

Closed

Description

@haha3344

I'm using ThreadSafeFunction to implement callbacks from CPP to JS. If an exception occur in JavaScript, it will be threw in CPP, but not JS.

The test project can be found here

Environment

  • ubuntu 18.06
  • node 10.16.3
  • node-addon-api 1.0.0

SyncCallback Example(the right way)

  • cpp code
// https://github.com/nodejs/node-addon-examples/tree/master/3_callbacks/node-addon-api
void SyncCallback(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();
  Napi::Function cb = info[0].As<Napi::Function>();
  cb.Call(env.Global(), {Napi::String::New(env, "hello SyncCallback ")});
}
  • js code, let s = sssss will throw an exception
function callBack(msg) {
  console.log(msg);
  let s = sssss
  console.log(msg);
}

addon.syncCallback(callBack);
  • run the JS code, it will throw an exception in JS
hello SyncCallback 
/home/haha/node-addon-api/addon.js:13
addon.syncCallback(callBack);
      ^

ReferenceError: sssss is not defined
    at callBack (/home/YaoXin19/node-addon-api/addon.js:5:11)
    at Object.<anonymous> (/home/YaoXin19/node-addon-api/addon.js:13:7)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)

AsyncCallback using ThreadSafeFunction

  • cpp code
// https://github.com/nodejs/node-addon-api/blob/master/doc/threadsafe_function.md
Napi::ThreadSafeFunction tsfn;
std::thread nativeThread;
void AsyncCallback(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();

  tsfn= Napi::ThreadSafeFunction::New(
			info.Env(),
			info[0].As<Napi::Function>(),  // JavaScript function called asynchronously
			"Resource Name",         // Name
			0,                       // Unlimited queue
			1,                       // Only one thread will use this initially
			[](Napi::Env) {        // Finalizer used to clean threads up
			  nativeThread.join();
		});

    nativeThread = std::thread([](){
      auto callback = []( Napi::Env env, Napi::Function jsCallback) {
      //try {
        jsCallback.Call(env.Global(), {Napi::String::New(env, "hello AsyncCallback")});
      //} catch(const std::exception& e) {
      // }
    };

    napi_status status = tsfn.BlockingCall(callback );
    tsfn.Release();
  });
}
  • js code, let s = sssss will throw an exception
function callBack(msg) {
  console.log(msg);
  let s = sssss
  console.log(msg);
}
addon.asyncCallback(callBack);
  • run the JS code, the exception is threw in CPP
hello AsyncCallback
terminate called after throwing an instance of 'Napi::Error'
  what():  sssss is not defined
Aborted (core dumped)

Question

When using ThreadSafeFunction, how to throw exceptions in JS like the SyncCallback Example?

Activity

  1. changed the title [-]ThreadSafeFunction : The exception was threw in CPP, but not JS.[/-] [+]ThreadSafeFunction : The exception is threw in CPP, but not JS.[/+] on Feb 9, 2020
  2. legendecas commented on Feb 9, 2020

    @legendecas
    Member

    How would you like to handle the thrown errors in an async way? They cannot be caught with try...catch block.

  3. haha3344 commented on Feb 10, 2020

    @haha3344
    Author

    How would you like to handle the thrown errors in an async way? They cannot be caught with try...catch block.

    I mean to use the simple example above to show my problem.

    I do this becasue I have a CPP addon, which has a worker thread to callback some data and I need to transform these data from CPP to JS.

    When using ThreadSafeFunction, the async callback works.

    Then I need to write some JS code to deal with these data. If I make some mistakes in JS code, the exception will be thrown in CPP, but not in JS.

    Is there a way to handle the exception in JS, but not in CPP?

    Thank you.

  4. legendecas commented on Feb 10, 2020

    @legendecas
    Member

    The error was thrown into c++ (which is not quite accurate, the errors are still on JavaScript land, but c++ addon have to handle it or the process had to crash) because the one who called the throwing JavaScript function is the c++ addon.

    You may wrap the JavaScript callback to handle the exceptions early in JavaScript:

    function wrap(fn) {
      return function wrapper(...args) {
        try {
          return fn.apply(this, args);
        } catch (e) {
          // do what you'd like to do with the error `e` here.
        }
      };
    }
    function callback(msg) {
      console.log(msg);
      let s = sssss
      console.log(msg);
    }
    addon.asyncCallback(wrap(callback));
  5. haha3344 commented on Feb 10, 2020

    @haha3344
    Author

    @legendecas Thanks for you reply. It works.

  6. haha3344 commented on Feb 11, 2020

    @haha3344
    Author

    Sorry to open this issue again.

    Using the wrap function, I can catch the exceptions early in JavaScript.

    But I still have an another question.

    When I use the CPP addon in electron, the syncCallback could show the exception on the DevTools like this

    1

    but the asyncCallback with wrap wouldn't. If I throw the exception in the CATCH block again, it makes the electron demo crash. asyncCallback without wrap make the electron demo crash directly.

    Is there way to make the asyncCallback do the same way like syncCallback in electron?
    Showing the exceptions on the DevTools and do not make the electron crash.

    The electron demo can be found here

  7. legendecas commented on Feb 11, 2020

    @legendecas
    Member

    You can print the error with console.error.

  8. haha3344 commented on Feb 11, 2020

    @haha3344
    Author

    @legendecas Thanks for your reply.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions