Promise and Add-on, Think Asynchronously with Callback!

来源:互联网 发布:顶尖电子称软件下载 编辑:程序博客网 时间:2024/05/14 16:43

Normally, when writing an Add-on, we could code like this:

// Somewherevoid doSomething(std::string& str) {    str = "Hello, world";}/// The implementation of add-onstatic void fork(const FunctionCallbackInfo<Value>& args) {    Isolate* iso = args.GetIsolate();    /// Do something    doSomething(str);    /// Callback    Local<Value> val = args[3]; // Assuming the forth arguments is the callback function.    if (val->IsFunction()) {        Local<Function> func = Function::Cast(val);        func->Call(iso->GetCurrentContext()->Global(), Integer::New(iso, 0x1234));    }} // end of fork

The above code works fine unless Promise involved. The notorious segment fault will occur. Because the Promise.resolve will probably come back from a different thread, so some changes must be made:

/// Turn our processing into async// Define the prototype of callback.using callback = boost::function<void(int, const std::string&)>;typedef struct {    std::string value;    callback cb;} async_struc;AsyncWorker<async_struc> async_worker;void doSomething(std::string& arg, const callback& cb {    async_struc* data = new async_struc();    data.value = arg;    data.cb = cb;    async_worker.post(data, [&](async_struc* x) {        // Do the work.        x->value += "Hello, world!";    }, [&](async_struc* x, bool canceled) {        x->cb(canceled ? -1 : 0, x->value);    });}

When crossing thread boundary, we have to wrap JavaScript object with Persistent. But v8 forbids us using explicit ctor of Persistent. An alternative is using a structure to hold the Persistent wrapped object and pass a structure pointer to make lambda expression capture it.
The structure looks like :

typedef struct {    std::string value; //<! The value came from arguments.    Persistent<Function> cb;} js_callback_info_t;

Also, following v8 reference, we should get current Isolate object under different threads. A HandleScope is needed too.

Isolate* asyncIso = Isolate::GetCurrent();HandleScope scope(asyncIso);

Now rewrite the js add-on method:

static void fork(const FunctionCallbackInfo<Value>& args) {    Isolate* iso = args.GetIsolate();    // Get string argument    String::Utf8Value utf8str(args[0]);    std::string str(*utf8str);    /// Save the callback information    Local<Value> val = args[3]; // Assuming the forth arguments is the callback function.    js_callback_info_t* cb_info = new js_callback_info();    cb_info->value = str;    cb_info->cb.Reset(iso, Local<Function>::Cast(val);    doSomething(str, [&, cb_info](int err, const std::string& res) mutable {        Isolate* asyncIso = Isolate::GetCurrent();        HandleScope scope(asyncIso);        Local<Function> func = Local<Function>::New(asyncIso, cb_info->cb);        Local<Value> params[] = { Integer::New(asyncIso, err), String::NewUtf8(asyncIso, res.c_str()) };        func->Call(asyncIso->GetCurrentContext()->Global(), 2, params);        // Dispose persistent object        func->cb.Reset();        // Release the memory allocated before        delete cb_info;    });} // end of fork

Now the Add-on is Promise-ready.

Good luck!

0 0
原创粉丝点击