How to call C++ function from JavaScript asynchronously

972 views
Skip to first unread message

Andrii Heonia

unread,
Mar 4, 2016, 12:57:19 PM3/4/16
to emscripten-discuss

How can I call C++ callback asynchronously from JavaScript?


This is my JS code:


<script type="text/javascript">
 
function sendRequest(callback) {  
    setTimeout
(function(){
      callback
["sayHi"]();
   
}, 100);
 
}
</script>


This is my C++ code:


#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;
}


When I execute this code in browser it fails with error:

Uncaught BindingError: Cannot pass deleted object as a pointer of type MyClass*


I use emcc 1.35.22 and compile it with this command:

~/app/emsdk_portable/emscripten/tag-1.35.22/emcc main.cpp --bind -o out.js


Thank you in advance!

Brion Vibber

unread,
Mar 4, 2016, 1:45:15 PM3/4/16
to emscripten Mailing List
Two things:

First, you need to make sure the C runtime doesn't shut down when main() exits -- see https://kripken.github.io/emscripten-site/docs/api_reference/module.html#Module.noExitRuntime

Second, you need to make sure your object doesn't go out of scope and get deleted at the end of the main() function. You'll have to store it in a global variable or something.

-- brion

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Andrii Heonia

unread,
Mar 7, 2016, 6:49:10 AM3/7/16
to emscripten-discuss
Hello Brion,

Thank you for your answer. I've changed a bit my example (now noExitRuntime=true and callback is global) but it still doesn't work. My callback dies before async call (and I don't get how to keep it alive). You can find my code here. What I'm doing wrong? 

Thanks in advance!
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

Charles Vaughn

unread,
Mar 7, 2016, 10:57:24 AM3/7/16
to emscripten-discuss
Hello ANdrii,

Your code flows like this:

1. Emscripten's main is called
2. myObj is created within the scope of main
3. sendRequest is called with myObj as its parameter
4. sendRequest sets a timeout to call "sayHi" on myObj
5. main returns, destroying myObj
100ms later
6. The timeout fires, trying to access myObj

You can create myObj with a static lifetime or heap allocate it and return a smart pointer.

Andrii Heonia

unread,
Mar 7, 2016, 12:50:06 PM3/7/16
to emscripte...@googlegroups.com
Hello Charles,

This is demo with global callback: https://github.com/AndriiHeonia/async-emcc/tree/7207aebdcc65b5d183f1a26516ccdd77eb06ce8e and it also doesn't work. My callback dies before async call even if it is global (and I don't get how to keep it alive)

Best regards,
Andrii

To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to a topic in the Google Groups "emscripten-discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/emscripten-discuss/8bzdVaR_lEE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to emscripten-disc...@googlegroups.com.

Brion Vibber

unread,
Mar 8, 2016, 1:52:02 PM3/8/16
to emscripten Mailing List
On Mon, Mar 7, 2016 at 9:50 AM, Andrii Heonia <a.he...@gmail.com> wrote:
This is demo with global callback: https://github.com/AndriiHeonia/async-emcc/tree/7207aebdcc65b5d183f1a26516ccdd77eb06ce8e and it also doesn't work. My callback dies before async call even if it is global (and I don't get how to keep it alive)

Yeah, I'm seeing the same thing with this example, can't quite see what's forcing the object to get deleted after the sync call code-path. Seems the same if I switch from raw pointers to std::shared_ptr...

Andrii, if you can't get this worked out I would recommend switching from storing the Callback in a C++ global to instantiating an App object from the JS side and letting the Callback instance live as a member variable in the App instance.

This should allow you to control the lifetime of the App instance from the JS side more explicitly (eg, it should stay alive until you explicitly destroy it from JS).

-- brion

Andrii Heonia

unread,
Mar 9, 2016, 3:46:27 AM3/9/16
to emscripten-discuss
Hi Brion,

I tried to add callback to the App as a member (m_cb) but it doesn't help. App still alive but callback dies somewhere inside m_requestManager.call<void>("sendRequest", m_cb).

I suspect that inside call method we have a copy of m_call instead of reference to m_call and this copy dies when we get out from the JS function scope (but m_cb still alive as a member of App), but I can be wrong...

I created an issue in Emscripten repo: https://github.com/kripken/emscripten/issues/4154
Reply all
Reply to author
Forward
0 new messages