Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving a function callback in v8 and Node.js

How would you save a javascript supplied callback in a v8 wrapped object for future use not only in the current function call. Essentially i want to create a javascript object in C++ and when created with new Object() supply a function callback. Then use that callback throughout the c++ objects life. See example below:

The issue im having is when I try to use the Handle object in a different static function it seg faults.

In node js file:

var Object = require("./customModule");
var obj = new Object(function(){console.log("Callback called...")})

// Emit callback
obj.emitCallback();

In c++ module header

class Object : public node::ObjectWrap {

public:

    static void Init(v8::Handle<v8::Object> target);

    Object();

protected:

    v8::Handle<v8::Function> m_faceDetectCallback;

    static v8::Handle<v8::Value> New(const v8::Arguments& args);

    static v8::Handle<v8::Value> onEmitCallback(const v8::Arguments& args);
}



v8::Handle<v8::Value> Object::New(const v8::Arguments& args) {

    HandleScope scope;

    Object* obj = new Object();
    obj->Wrap(args.This());

    obj->m_faceDetectCallback = Handle<Function>::Cast(args[0]);

    //obj->m_faceDetectCallback = v8::Persistent<Function>::Cast(args[0]);

    // Works fine here.
    const unsigned argc = 1;
    Local<Value> argv[argc] = { Local<Value>::New(String::New("hello world")) };
    obj->m_faceDetectCallback->Call(Context::GetCurrent()->Global(), argc, argv);

    return args.This();
}

static v8::Handle<v8::Value> Object::onEmitCallback(const v8::Arguments& args){
    HandleScope scope;

    Object* obj = ObjectWrap::Unwrap<Object>(args.This());

    const unsigned argc = 1;
    Local<Value> argv[argc] = { Local<Value>::New(String::New("hello world")) };

        //!! Segfaults here
    if(obj->m_faceDetectCallback->IsCallable()){
        //obj->m_faceDetectCallback->Call(Context::GetCurrent()->Global(), argc, argv);
    }


    return scope.Close(v8::String::New("Start called"));
}
like image 452
Adam Magaluk Avatar asked Oct 15 '12 01:10

Adam Magaluk


People also ask

How do I call a callback function in node JS?

For example: In Node. js, when a function start reading file, it returns the control to execution environment immediately so that the next instruction can be executed. Once file I/O gets completed, callback function will get called to avoid blocking or wait for File I/O.

Why does node js use V8?

V8 is required for the current Node. js engine to function. In the absence of V8, it wouldn't have a JavaScript engine, and thus wouldn't be able to run JavaScript code. The V8 interface between C++ and JavaScript is used by the native code bindings that come with Node.

Why do we use callback functions extensively in node JS?

In node. js, we basically use callbacks for handling asynchronous operations like – making any I/O request, database operations or calling an API to fetch some data. Callback allows our code to not get blocked when a process is taking a long time.

What is V8 engine in node JS?

What is V8? V8 is Google's open source high-performance JavaScript and WebAssembly engine, written in C++. It is used in Chrome and in Node.js, among others. It implements ECMAScript and WebAssembly, and runs on Windows 7 or later, macOS 10.12+, and Linux systems that use x64, IA-32, ARM, or MIPS processors.


1 Answers

You need to use v8::Persistent instead of a standard handle. Handle is the base class for Local and Persistent so by doing the cast that you are doing, you are grabbing a pointer to the v8::Function but not doing anything that would tell V8 not to garbage-collect it.

With this in your class:

v8::Persistent<v8::Function> m_faceDetectCallback;

and assigned with

obj->m_faceDetectCallback = v8::Persistent<v8::Function>::New(args[0]);
like image 72
loganfsmyth Avatar answered Oct 26 '22 23:10

loganfsmyth