我对Emscripten提出了一个小问题。 如何从JavaScript中异步调用C ++回调?
这是我的JS代码:
<script type="text/javascript">
function sendRequest(callback) {
setTimeout(function(){
callback["sayHi"]();
}, 100);
}
</script>
这是我的C ++代码:
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>
using namespace emscripten;
class MyClass {
public:
void sayHi () {
printf("Hello! \n");
};
};
EMSCRIPTEN_BINDINGS(MyClass)
{
class_<MyClass>("MyClass")
.function("sayHi", &MyClass::sayHi);
}
int main() {
val window = val::global("window");
auto myObj = MyClass();
window.call<void>("sendRequest", myObj);
return 0;
}
当我执行此代码时,它失败并显示错误:
Uncaught BindingError: Cannot pass deleted object as a pointer of type MyClass*
我使用emcc 1.35.22并使用以下命令编译它:
~/app/emsdk_portable/emscripten/tag-1.35.22/emcc main.cpp --bind -o out.js
答案 0 :(得分:1)
出于某种原因,当你打电话
window.call<void>("sendRequest", myObj);
当堆栈从上面的行中清除时,Emscripten / embind删除myObj
(如果你向MyClass添加一个析构函数,你可以看到这个。)
第二个问题是,即使Emscripten / embind没有这样做,当你这样做时
auto myObj = MyClass();
在main
中,在堆栈上创建了myObj
,因此它将在异步回调之前的main
末尾被删除。
解决这两个问题的方法是在堆上创建对象,将其作为原始指针传递给Javascript,以及指向静态回调的函数指针。您可以使用EM_ASM_ARGS
从C ++调用,然后使用dynCall_*
函数从Javascript中调用函数指针。
例如,C ++就像
void callback(MyClass *myObj)
{
myObj->sayHi();
}
MyClass *myObj;
int main() {
myObj = new MyClass();
EM_ASM_ARGS({
sendRequest($0, $1);
}, &callback, myObj);
// myObj is still in memory
// be sure to delete it
return 0;
}
和Javascript
Module = {
noExitRuntime: true
};
function sendRequest(callback, myObj) {
setTimeout(function() {
Module.dynCall_vi(callback, myObj);
}, 1000);
}