Page 1 of 2

Execute method on other thread and get result to JS

PostPosted: Sun Jun 27, 2021 12:36 pm
by prsolucoes
Hi,

How to execute a method on other thread and get result to Javascript?

Im using this example in mind (i don't know if it is the best example):
https://chromium.googlesource.com/chrom ... ing-a-task

I want call C++ function from javascript like im already do here:
https://github.com/paulo-coutinho/cef-s ... me.vue#L94

But i want now execute a long time function without block browser and return the result/callback to javascript function. Something like this:

Code: Select all
var result = MyApp.longTask("my param 1", "my param 2");
console.log(result);

// or

MyApp.longTask("my param 1", "my param 2").then((result) => {
    console.log(result);
}).catch((error) => {
    console.log(error);
});


Can anyone help me?

Thanks.

Re: Execute method on other thread and get result to Javascr

PostPosted: Sun Jun 27, 2021 9:13 pm
by prsolucoes
Hi,

I tried this:

Code: Select all
#include "main/v8/AppExtension.hpp"

#include <chrono>
#include <ctime>
#include <iostream>

namespace v8
{

class NotifyTask : public CefTask
{
public:
    NotifyTask(CefRefPtr<CefV8Context> context, CefRefPtr<CefV8Value> callback) : callback(callback), context(context) {}

    void Execute() override
    {
        CefV8ValueList args;
        args.push_back(CefV8Value::CreateString("12345"));
        callback->ExecuteFunctionWithContext(context, NULL, args);
    }

private:
    CefRefPtr<CefV8Value> callback;
    CefRefPtr<CefV8Context> context;

    IMPLEMENT_REFCOUNTING(NotifyTask);
};

bool AppV8ExtensionHandler::Execute(const CefString &name, CefRefPtr<CefV8Value> object, const CefV8ValueList &arguments, CefRefPtr<CefV8Value> &retval, CefString &exception)
{
    if (name == "getStuffMessage")
    {
        retval = CefV8Value::CreateString("A stuff message from C++");
        return true;
    }
    else if (name == "getCurrentTime")
    {
        std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
        char buf[100] = {0};
        std::strftime(buf, sizeof(buf), "%Y-%m-%d %r", std::localtime(&now));
        std::string value = std::string(buf);
        retval = CefV8Value::CreateString(value.c_str());
        return true;
    }
    else if (name == "longTask")
    {
        retval = CefV8Value::CreateNull();

        if (arguments.size() == 1 && arguments[0]->IsFunction())
        {
            CefRefPtr<CefV8Value> func = arguments[0];
            CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
            CefRefPtr<CefTaskRunner> taskRunner = CefTaskRunner::GetForCurrentThread();

            taskRunner->PostTask(new NotifyTask(context, func));

            return true;
        }
        else
        {
            exception = "Function Not Supported";
        }

        return false;
    }

    return false;
}

void AppV8ExtensionHandler::init()
{
    // register a V8 extension with the below JavaScript code that calls native methods implemented in the handler
    std::string code =
        ""
        "var MyApp;"
        "if (!MyApp) {"
        "  MyApp = {};"
        "}"
        ""
        "(function() {"
        "  MyApp.getStuffMessage = function() {"
        "    native function getStuffMessage();"
        "    return getStuffMessage();"
        "  };"
        "  MyApp.getCurrentTime = function() {"
        "    native function getCurrentTime();"
        "    return getCurrentTime();"
        "  };"
        "  MyApp.longTask = function(params) {"
        "    native function longTask(params);"
        "    return longTask(params);"
        "  };"
        ""
        "})();";

    CefRegisterExtension("v8/app", code, new v8::AppV8ExtensionHandler());
}

} // namespace v8


But when i try call i only receive error:


Code: Select all
longTask() {
      MyApp.longTask()
        .then((result) => {
          this.message = result;
        })
        .catch((e) => {
          this.message = "Error: " + e;
        });
},

longTask2() {
      MyApp.longTask(function (result) {
        this.message = result;
      });
},


Can anyone help me?

Re: Execute method on other thread and get result to JS

PostPosted: Mon Jun 28, 2021 12:18 am
by prsolucoes
After a lot of search on forum, slack, google etc - it don't work.

I put my sample code here:
https://github.com/paulo-coutinho/cef-s ... ension.cpp

If anyone help me, please post here.

Re: Execute method on other thread and get result to JS

PostPosted: Mon Jun 28, 2021 11:18 am
by magreenblatt
JavaScript native bindings can only be used on the main renderer process thread. You will need to use some other approach for the execution (like WebWorker, async execution, etc) that then calls back to the native bindings on the main thread.

Re: Execute method on other thread and get result to JS

PostPosted: Mon Jun 28, 2021 3:29 pm
by prsolucoes
magreenblatt wrote:JavaScript native bindings can only be used on the main renderer process thread. You will need to use some other approach for the execution (like WebWorker, async execution, etc) that then calls back to the native bindings on the main thread.


Hi,

Ok @magreenblatt,

But do you have any example?

I make one try but didnt work:
https://github.com/paulo-coutinho/cef-s ... ension.cpp

I searched all places and don't find any answer about it that make me understand how i can do it.

Re: Execute method on other thread and get result to JS

PostPosted: Mon Jun 28, 2021 5:11 pm
by magreenblatt
You can find examples of async JS bindings here.

Re: Execute method on other thread and get result to JS

PostPosted: Mon Jun 28, 2021 7:00 pm
by prsolucoes
magreenblatt wrote:You can find examples of async JS bindings here.


I already read it 234343 times.

But don't understand how it works. Can you help me?

Re: Execute method on other thread and get result to JS

PostPosted: Tue Jun 29, 2021 9:25 pm
by prsolucoes
Hi,

I made an example and it is working:
https://github.com/paulo-coutinho/cef-s ... inding.cpp

But i have a question: Im storing the browser callback in the request, because when request finish i have the browser callback. There is any problem?
https://github.com/paulo-coutinho/cef-s ... Client.cpp

Thanks.

Re: Execute method on other thread and get result to JS

PostPosted: Tue Jun 29, 2021 9:53 pm
by magreenblatt
What type of object is the browser callback? Any V8 objects need to be released by the time the associated context is released (OnContextReleased called).

Re: Execute method on other thread and get result to JS

PostPosted: Wed Jun 30, 2021 3:48 pm
by prsolucoes
magreenblatt wrote:What type of object is the browser callback? Any V8 objects need to be released by the time the associated context is released (OnContextReleased called).


https://github.com/paulo-coutinho/cef-s ... nt.cpp#L10

Browser Callback Is
Code: Select all
CefRefPtr<CefMessageRouterBrowserSide::Callback> browserCallback


Request Callback Is:
Code: Select all
typedef base::Callback<void(CefRefPtr<CefMessageRouterBrowserSide::Callback> /* browserCallback */, CefURLRequest::ErrorCode /*errorCode*/, const std::string & /*downloadData*/)> RequestCallback;


There is nothing related to V8 here, only binding objects. Im not sure about store browser callback that is the callback of binding.

What do you think?