【问题标题】:Asynchronously calling a callback function in Spidermonkey JS engineSpidermonkey JS引擎中异步调用回调函数
【发布时间】:2026-02-21 07:25:01
【问题描述】:

使用 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

并检查了这个 * 帖子Spidermonkey and Garbage Collection

甚至尝试让 JS 回调函数成为一个永远不应该被垃圾回收的全局函数。 (但这不是我想要的。)

【问题讨论】:

  • 你有没有考虑加入 mozilla ircwiki.mozilla.org/IRC我怀疑那里的人会立即为您提供帮助。

标签: javascript c++ spidermonkey


【解决方案1】:

您在尝试异步调用函数时没有提及程序的行为,但我认为在尝试调用该函数时它会出现段错误,因为 GC 可能已经移动了它。您需要一种方法来存储函数 object (它不是代码中的值)。 JS::Rooted 在这种情况下是不可接受的,因为堆栈生根期望 gc 事物以 LIFO 顺序生根。因此,您需要将其存储在JS::Heap&lt;JSObject*&gt; 句柄中。 JS::Heap 句柄希望存在于堆而不是堆栈上(可能在列表或树结构中)。 JS::Heap 句柄的警告是它们需要由 GC 跟踪,以便可以重新定位基础对象并更新句柄。跟踪在this question 中讨论。

假设您的对象现在已正确存储和跟踪,您应该可以随时调用它而不会出现任何问题。

【讨论】: