使用Spidermonkey v27:
从C ++中“保留”然后异步调用临时JS函数的正确方法是什么?
JS代码:
myFunction(function(){
console.log("The function works");
});
C ++代码:
bool js_myFunction(JSContext* cx, uint32_t argc, jsval* vp)
{
if (argc == 1)
{
implement_async_function(cx, vp);
JS_SET_RVAL(cx, vp, JSVAL_NULL);
return true;
}
return false;
}
static JSContext* savedContext;
static jsval* savedVal;
void implement_async_function(JSContext* cx, jsval* vp)
{
// if the function is called immediately, everything is okay!
jsval retVal;
JS_CallFunctionValue(cx, nullptr, *vp, 0, nullptr, &retVal);
// "The function works"
// if some work has to be done before calling the callback...
savedContext = cx;
savedVal = vp;
start_async_process();
}
void async_process_complete()
{
jsval retVal;
JS_CallFunctionValue(savedContext, nullptr, *savedVal, 0, nullptr, &retVal);
// "<no filename="filename">:0:true is not a function"
// or else it crashes...
}
void alternate_implement_async_function(JSContext* cx, jsval* vp)
{
// also tried this:
savedContext = cx;
savedVal = vp;
JS_AddValueRoot(savedContext, savedVal);
start_async_process();
// and this:
savedContext = cx;
savedVal = new jsval(*vp);
JS_AddValueRoot(savedContext, savedVal);
start_async_process();
// and using JS::RootedValue
// and using JS::Heap<JS::Value>
// and using the global context instead of the saved context
}
我读过SpiderMonkey的文件:
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_Reference/JS::Value
https://developer.mozilla.org/en-US/docs/SpiderMonkey/GC_Rooting_Guide
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference/JS_AddRoot
https://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_Reference/JS_CallFunctionValue
并检查了此StackOverflow帖子Spidermonkey and Garbage Collection
甚至尝试将JS回调函数作为一个永远不会被垃圾回收的全局函数。 (这不是我想要的。)
答案 0 :(得分:1)
在尝试异步调用函数时,您没有提到程序的行为,但我认为在尝试调用函数时它会出错,因为GC可能已经移动了它。您需要一种方法来存储函数 object (它不是代码中的值)。在这种情况下,JS::Rooted
是不可接受的,因为堆栈生根期望gc的东西在LIFO排序中生根。因此,您需要将其存储在JS::Heap<JSObject*>
句柄中。 JS::Heap
句柄期望存在于堆而不是堆栈中(可能在列表或树结构中)。使用JS::Heap
句柄的警告是它们需要由GC跟踪,以便可以重新定位基础对象并更新句柄。跟踪在this question中进行了讨论。
假设您的对象现在已正确存储并跟踪,您应该可以随时调用它而不会出现任何问题。