如果承诺已解决,如何签入 node.js C++ 插件
How to check in an node.js C++ addon, if a promise is resolved
任务:
我从 C++ 调用一个 return 一个 v8::Promise 的回调(所以是一个异步函数)。
现在我想知道承诺是否已解决。
对于此处的示例,我想从 JS 检查承诺是否已解决。
但是 "just beeing informed in the C++ addon" 就可以了。
问题:
我未能在 C++ 中创建持久性 Promise 对象。
我还在事件循环中工作。但是当我稍后再次进入事件循环时,对象是空的。
代码:
JS测试代码
// create an object in the addon
var OB = require('./build/Debug/objectwraphandle.node')
var obj = new OB.MyObject(42)
// just an async wait function
async function asyncFunc1(y) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('asyncFunc1: DONE'), 2000);
});
}
// pass the async function as callback to the addon and call it
obj.callAsyncFunction(asyncFunc1);
// ask the object, it the promise is already resolved.
// this should switch from 1 (Pending) to 0 (Resolved) after 2 seconds
console.log(" resolved? : " + obj.isPromiseResolved());
// but this core-dumps with:
// "FATAL ERROR: v8::Promise::Cast Could not convert to promise"
现在是 C++ 方面(顺便说一下 - 不用说我既不是 C++ 也不是 JS 大师)
(原文取自 NAN - Node.js 的原生抽象)。
为了复制,我把完整的代码放在这里。重要的是函数 CallAsyncFunction 和 IsPromiseResolved.
/*********************************************************************
* NAN - Native Abstractions for Node.js
* Copyright (c) 2018 NAN contributors
* MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
*
* and now here: used as test basis by Gerrit Prange
********************************************************************/
#include <iostream>
#include <nan.h>
using namespace Nan;
class MyObject : public ObjectWrap {
public:
static NAN_MODULE_INIT(Init) {
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New("MyObject").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// these are the two functions in question
SetPrototypeMethod(tpl, "callAsyncFunction", CallAsyncFunction);
SetPrototypeMethod(tpl, "isPromiseResolved", IsPromiseResolved);
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
Set(target, Nan::New("MyObject").ToLocalChecked(),
Nan::GetFunction(tpl).ToLocalChecked());
}
private:
explicit MyObject(double value = 0) : value_(value) {}
~MyObject() {}
// here: the promise is stored as persistent object
Nan::Persistent<v8::Promise> *persistentPromise;
static NAN_METHOD(New) {
if (info.IsConstructCall()) {
double value = info[0]->IsUndefined() ? 0 : Nan::To<double>(info[0]).FromJust();
MyObject *obj = new MyObject(value);
obj->Wrap(info.This());
info.GetReturnValue().Set(info.This());
} else {
const int argc = 1;
v8::Local<v8::Value> argv[argc] = {info[0]};
v8::Local<v8::Function> cons = Nan::New(constructor());
info.GetReturnValue().Set(
Nan::NewInstance(cons, argc, argv).ToLocalChecked());
}
}
/* we get a callback function (async function),
* call this callback and get a promise returned
*/
static NAN_METHOD(CallAsyncFunction) {
MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.Holder());
const unsigned argc = 1;
v8::Local<v8::Value> argv[argc] = { Nan::New("hello world").ToLocalChecked() };
Callback cb(To<v8::Function>(info[0]).ToLocalChecked());
// call the callback - and get a Promise
Nan::MaybeLocal<v8::Value> promiseReturnValue = (*cb)->Call(GetCurrentContext()->Global(), argc, argv);
// check if the promise is already resolved. (should not be in this example!)
v8::Handle<v8::Promise> promiseReturnObject = v8::Handle<v8::Promise>::Cast ( promiseReturnValue.ToLocalChecked() );
v8::Promise::PromiseState promiseState = promiseReturnObject->State();
std::cout << " state: " << promiseState << std::endl;
// make the callback persistent
Nan::Persistent<v8::Promise> persistentPromiseReturnObject(promiseReturnObject);
obj->persistentPromise = &persistentPromiseReturnObject;
}
/* check if the callback is already resolved and return the state
*/
static NAN_METHOD(IsPromiseResolved) {
MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.Holder());
v8::Local<v8::Context> context = v8::Isolate::GetCurrent()->GetCurrentContext();
// get the persistent callback and convert it into a local object
v8::Local<v8::Object> objectToCheckPromise = Nan::New ( *obj->persistentPromise );
// THE LINE BELOW IS THE PROBLEM! actually, persiting does not seem to work.
v8::Local<v8::Promise> promiseObject = v8::Local<v8::Promise>::Cast ( objectToCheckPromise );
// get the promises state
v8::Promise::PromiseState promiseState = promiseObject->State();
// and return the state
std::cout << " in IsPromiseResolved state: " << promiseState << std::endl;
info.GetReturnValue().Set(Nan::New(promiseState));
}
static inline Persistent<v8::Function> & constructor() {
static Persistent<v8::Function> my_constructor;
return my_constructor;
}
double value_;
};
NODE_MODULE(objectwraphandle, MyObject::Init)
我得到的实际错误是:
FATAL ERROR: v8::Promise::Cast Could not convert to promise
1: node::Abort() [node]
2: 0x121a2cc [node]
3: v8::Utils::ReportApiFailure(char const*, char const*) [node]
4: v8::Promise::Cast(v8::Value*) [/home/gpr/projects/own/nodejs/jsFromC_NAN_PromiseWait/build/Debug/objectwraphandle.node]
5: v8::Local<v8::Promise> v8::Local<v8::Promise>::Cast<v8::Object>(v8::Local<v8::Object>) [/home/gpr/projects/own/nodejs/jsFromC_NAN_PromiseWait/build/Debug/objectwraphandle.node]
6: MyObject::IsPromiseResolved(Nan::FunctionCallbackInfo<v8::Value> const&) [/home/gpr/projects/own/nodejs/jsFromC_NAN_PromiseWait/build/Debug/objectwraphandle.node]
7: 0x7fb4dd8889dc [/home/gpr/projects/own/nodejs/jsFromC_NAN_PromiseWait/build/Debug/objectwraphandle.node]
8: v8::internal::FunctionCallbackArguments::Call(void (*)(v8::FunctionCallbackInfo<v8::Value> const&)) [node]
9: 0xb9043c [node]
10: v8::internal::Builtin_HandleApiCall(int, v8::internal::Object**, v8::internal::Isolate*) [node]
抱歉,这是一篇长文post。 (但我想把代码放在这里——如果有人想试试这个的话。)
好的,看来 v8 Promise 不是一个可以持久化的对象。
但是你可以这样做:
向 promise 添加 resolve 和 reject 回调,以便在 promise resolved/rejected 时得到通知。
(我本来想添加 "direct c++ callbacks" 而不是必须通过 JS,但现在没问题。)
或者您在代码中创建一个解析器,它可以持久化,您可以稍后在代码中解析或拒绝您的解析器。
(对我来说,这是解决我的问题的另一种方法 - 也许朝那个方向看对你也有帮助?)
您可以将 Promise 存储在持久句柄中。您的代码应该类似于:
class MyObject : public ObjectWrap {
// ...
private:
Nan::Persistent<Promise> persistentPromise; // not a pointer!
}
NAN_METHOD(CallAsyncFunction) {
MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.Holder());
// ... your function call here
// returnobj is a Local<Object>
Local<Promise> p = Local<Promise>::Cast(returnobj);
obj->persistentPromise.Reset(p);
}
NAN_METHOD(IsPromiseResolved) {
MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.This());
Local<Promise> p = obj->persistentPromise.Get(Isolate::GetCurrent());
info.GetReturnValue().Set(p->State());
}
我不知道是否有正当理由将 v8 类型的地址或取消引用作为嵌入器(查看您的回调调用以及您如何设置持久句柄)。有 API 方法可以安全地执行这些操作。
顺便说一句,Handle
已弃用; Local
是它的替代品。
任务:
我从 C++ 调用一个 return 一个 v8::Promise 的回调(所以是一个异步函数)。 现在我想知道承诺是否已解决。
对于此处的示例,我想从 JS 检查承诺是否已解决。 但是 "just beeing informed in the C++ addon" 就可以了。
问题:
我未能在 C++ 中创建持久性 Promise 对象。 我还在事件循环中工作。但是当我稍后再次进入事件循环时,对象是空的。
代码:
JS测试代码
// create an object in the addon
var OB = require('./build/Debug/objectwraphandle.node')
var obj = new OB.MyObject(42)
// just an async wait function
async function asyncFunc1(y) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('asyncFunc1: DONE'), 2000);
});
}
// pass the async function as callback to the addon and call it
obj.callAsyncFunction(asyncFunc1);
// ask the object, it the promise is already resolved.
// this should switch from 1 (Pending) to 0 (Resolved) after 2 seconds
console.log(" resolved? : " + obj.isPromiseResolved());
// but this core-dumps with:
// "FATAL ERROR: v8::Promise::Cast Could not convert to promise"
现在是 C++ 方面(顺便说一下 - 不用说我既不是 C++ 也不是 JS 大师) (原文取自 NAN - Node.js 的原生抽象)。 为了复制,我把完整的代码放在这里。重要的是函数 CallAsyncFunction 和 IsPromiseResolved.
/*********************************************************************
* NAN - Native Abstractions for Node.js
* Copyright (c) 2018 NAN contributors
* MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
*
* and now here: used as test basis by Gerrit Prange
********************************************************************/
#include <iostream>
#include <nan.h>
using namespace Nan;
class MyObject : public ObjectWrap {
public:
static NAN_MODULE_INIT(Init) {
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
tpl->SetClassName(Nan::New("MyObject").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// these are the two functions in question
SetPrototypeMethod(tpl, "callAsyncFunction", CallAsyncFunction);
SetPrototypeMethod(tpl, "isPromiseResolved", IsPromiseResolved);
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
Set(target, Nan::New("MyObject").ToLocalChecked(),
Nan::GetFunction(tpl).ToLocalChecked());
}
private:
explicit MyObject(double value = 0) : value_(value) {}
~MyObject() {}
// here: the promise is stored as persistent object
Nan::Persistent<v8::Promise> *persistentPromise;
static NAN_METHOD(New) {
if (info.IsConstructCall()) {
double value = info[0]->IsUndefined() ? 0 : Nan::To<double>(info[0]).FromJust();
MyObject *obj = new MyObject(value);
obj->Wrap(info.This());
info.GetReturnValue().Set(info.This());
} else {
const int argc = 1;
v8::Local<v8::Value> argv[argc] = {info[0]};
v8::Local<v8::Function> cons = Nan::New(constructor());
info.GetReturnValue().Set(
Nan::NewInstance(cons, argc, argv).ToLocalChecked());
}
}
/* we get a callback function (async function),
* call this callback and get a promise returned
*/
static NAN_METHOD(CallAsyncFunction) {
MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.Holder());
const unsigned argc = 1;
v8::Local<v8::Value> argv[argc] = { Nan::New("hello world").ToLocalChecked() };
Callback cb(To<v8::Function>(info[0]).ToLocalChecked());
// call the callback - and get a Promise
Nan::MaybeLocal<v8::Value> promiseReturnValue = (*cb)->Call(GetCurrentContext()->Global(), argc, argv);
// check if the promise is already resolved. (should not be in this example!)
v8::Handle<v8::Promise> promiseReturnObject = v8::Handle<v8::Promise>::Cast ( promiseReturnValue.ToLocalChecked() );
v8::Promise::PromiseState promiseState = promiseReturnObject->State();
std::cout << " state: " << promiseState << std::endl;
// make the callback persistent
Nan::Persistent<v8::Promise> persistentPromiseReturnObject(promiseReturnObject);
obj->persistentPromise = &persistentPromiseReturnObject;
}
/* check if the callback is already resolved and return the state
*/
static NAN_METHOD(IsPromiseResolved) {
MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.Holder());
v8::Local<v8::Context> context = v8::Isolate::GetCurrent()->GetCurrentContext();
// get the persistent callback and convert it into a local object
v8::Local<v8::Object> objectToCheckPromise = Nan::New ( *obj->persistentPromise );
// THE LINE BELOW IS THE PROBLEM! actually, persiting does not seem to work.
v8::Local<v8::Promise> promiseObject = v8::Local<v8::Promise>::Cast ( objectToCheckPromise );
// get the promises state
v8::Promise::PromiseState promiseState = promiseObject->State();
// and return the state
std::cout << " in IsPromiseResolved state: " << promiseState << std::endl;
info.GetReturnValue().Set(Nan::New(promiseState));
}
static inline Persistent<v8::Function> & constructor() {
static Persistent<v8::Function> my_constructor;
return my_constructor;
}
double value_;
};
NODE_MODULE(objectwraphandle, MyObject::Init)
我得到的实际错误是:
FATAL ERROR: v8::Promise::Cast Could not convert to promise
1: node::Abort() [node]
2: 0x121a2cc [node]
3: v8::Utils::ReportApiFailure(char const*, char const*) [node]
4: v8::Promise::Cast(v8::Value*) [/home/gpr/projects/own/nodejs/jsFromC_NAN_PromiseWait/build/Debug/objectwraphandle.node]
5: v8::Local<v8::Promise> v8::Local<v8::Promise>::Cast<v8::Object>(v8::Local<v8::Object>) [/home/gpr/projects/own/nodejs/jsFromC_NAN_PromiseWait/build/Debug/objectwraphandle.node]
6: MyObject::IsPromiseResolved(Nan::FunctionCallbackInfo<v8::Value> const&) [/home/gpr/projects/own/nodejs/jsFromC_NAN_PromiseWait/build/Debug/objectwraphandle.node]
7: 0x7fb4dd8889dc [/home/gpr/projects/own/nodejs/jsFromC_NAN_PromiseWait/build/Debug/objectwraphandle.node]
8: v8::internal::FunctionCallbackArguments::Call(void (*)(v8::FunctionCallbackInfo<v8::Value> const&)) [node]
9: 0xb9043c [node]
10: v8::internal::Builtin_HandleApiCall(int, v8::internal::Object**, v8::internal::Isolate*) [node]
抱歉,这是一篇长文post。 (但我想把代码放在这里——如果有人想试试这个的话。)
好的,看来 v8 Promise 不是一个可以持久化的对象。
但是你可以这样做:
向 promise 添加 resolve 和 reject 回调,以便在 promise resolved/rejected 时得到通知。 (我本来想添加 "direct c++ callbacks" 而不是必须通过 JS,但现在没问题。)
或者您在代码中创建一个解析器,它可以持久化,您可以稍后在代码中解析或拒绝您的解析器。 (对我来说,这是解决我的问题的另一种方法 - 也许朝那个方向看对你也有帮助?)
您可以将 Promise 存储在持久句柄中。您的代码应该类似于:
class MyObject : public ObjectWrap {
// ...
private:
Nan::Persistent<Promise> persistentPromise; // not a pointer!
}
NAN_METHOD(CallAsyncFunction) {
MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.Holder());
// ... your function call here
// returnobj is a Local<Object>
Local<Promise> p = Local<Promise>::Cast(returnobj);
obj->persistentPromise.Reset(p);
}
NAN_METHOD(IsPromiseResolved) {
MyObject* obj = ObjectWrap::Unwrap<MyObject>(info.This());
Local<Promise> p = obj->persistentPromise.Get(Isolate::GetCurrent());
info.GetReturnValue().Set(p->State());
}
我不知道是否有正当理由将 v8 类型的地址或取消引用作为嵌入器(查看您的回调调用以及您如何设置持久句柄)。有 API 方法可以安全地执行这些操作。
顺便说一句,Handle
已弃用; Local
是它的替代品。