9

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"));
}
Adam Magaluk
  • 1,716
  • 20
  • 29

1 Answers1

13

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]);
loganfsmyth
  • 156,129
  • 30
  • 331
  • 251
  • Wow, this was causing me huge problems! Thanks a lot :) –  Dec 06 '12 at 16:14
  • 2
    It seems like with the current version of V8, you need to [specify copyable traits](http://stackoverflow.com/questions/22646546/how-to-store-persistent-handles-in-v8) for the persistent handle. – danijar Mar 26 '14 at 08:49
  • And how would you call this function afterward ? I have no idea what to pu in _faceDetectCallback->Call first argument – webaba Oct 03 '14 at 21:06
  • I used v8::Handle obj = v8::Context::GetCurrent()->Global() as a first argument and it worked fine. The first argument actually represents what to replace 'this' with when executing the js code of the function. – webaba Oct 05 '14 at 21:44
  • How to implement in v8 14.x version? – januw a Feb 14 '21 at 14:03