简体   繁体   中英

Pass JS function to C++ as function parameter

I want to make async call to C++ native function, but have some problems: when I call native function in async block (in Promise, exactly), it blocks UI thread and no async call is made. I want to pass callback to C++ function and call it. How can I pass function object?

class frame : public sciter::window {
public:
    frame() : window(SW_TITLEBAR | SW_RESIZEABLE | SW_CONTROLS | SW_MAIN | SW_ENABLE_DEBUG) {}

void assertion(const std::string& val)
{
    stream << std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count() 
        << ' '
        << val 
        << '\n';
    stream.flush();
}

void asyncFunction(::sciter::value callback)
{
    std::thread{ [callback]() 
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(5000)); // if I use it in same thread, it blocks UI thread and no async call is made
        // call callback function
    } }.detach();
}

SOM_PASSPORT_BEGIN(frame)
    SOM_FUNCS(
        SOM_FUNC(assertion),
        SOM_FUNC(asyncFunction)
    )
SOM_PASSPORT_END

private:
    std::ofstream stream{ "log.txt" };
};

In this implementation I use another thread to make a logic. But if I want to return values (or notify, that call has completed), I need fire event (what I don't want to do, because logic will be spread on whole code) or call some sort of callback. sciter::value have methods is_function_object and is_function , so, probably, I have opportinuty to cast value to the C++ function object. But how can I do this?

<html>
    <head>
        <title>Test</title>
    </head>
    <body>
        <button #test>Assert</button>
        <script>
            function sleep(time) {
                return new Promise(resolve => {
                    Window.this.frame.asyncFunction(function (result)
                    {
                        Window.this.frame.assertion(result);
                        resolve(result);
                    }); // resolve(Window.this.frame.asyncFunction()) blocks code execution until asyncFunction returns
            });
            }

            async function answer() {
                Window.this.frame.assertion("sleep start");
                await sleep(5000);
                Window.this.frame.assertion("sleep end");
                return 50;
            }

            document.$("button#test").onclick = function () {
                var p = answer();
                p.then(result => { Window.this.frame.assertion("Ended: " + result) });
                Window.this.frame.assertion("go next");
            }
        </script>
    </body>
</html>

Well, here are a few possibilities: we can use callback.call() if a function or function object was passed or just return Promise like object. Examples:

void asyncFunction(::sciter::value callback)
{
    std::thread{ [callback]() 
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(5000));
        sciter::value result = sciter::value(42);
        callback.call(result); // invoke the callback function.
    } }.detach();
}

That's how to call callback function. But we can simply return Promise like object (defined here ):

 sciter::value nativeAsyncFunction(int milliseconds)
  {
    sciter::om::hasset<NativePromise> promise = new NativePromise();

    std::thread([=]() {
       std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
       promise->resolve(42);
      }).detach();

    return sciter::value::wrap_asset(promise);
  }

In this case we don't need to create additional functions like sleep , we just call nativeAsyncFunction in answer and await its result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM