Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use callbacks for bindings to enable async behavior #2

Merged
merged 1 commit into from Mar 22, 2024

Conversation

nick-thompson
Copy link
Collaborator

Turns this:

m_webView->bind("example", [this](const choc::value::ValueView&) -> choc::value::Value {
    if (!isArrayWithNonZeroLength(args))
    {
        return {};
    }

    return doExample(args[0]);
});

into this

m_webView->bind("example", [this](const choc::value::ValueView& args, choc::ui::WebView::ReplyFn&& reply) {
    if (!isArrayWithNonZeroLength(args))
    {
        return reply({}, "Invalid arguments");
    }

    return reply(doExample(args[0]), {});
});

This leans into the already async behavior of choc's binding stuff, using a lambda to enable an async implementation that calls back when it has its value ready (i.e. after a bg thread has finished doing some work). This keeps the sync behavior already have, for cases where we need it, by just synchronously calling the replyFn when we have our value.

Copy link

@awood314 awood314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is demystifying!

@@ -135,7 +135,8 @@ class WebView
void navigate (const std::string& url);

/// A callback function which can be passed to bind().
using CallbackFn = std::function<choc::value::Value(const choc::value::ValueView& args)>;
using ReplyFn = std::function<void(choc::value::Value, std::string)>;
using CallbackFn = std::function<void(const choc::value::ValueView& args, ReplyFn&& reply)>;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clarifying question: in this new world, all functions would be required to call reply (at their leisure), and not be required to return anything. is that right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right!

@@ -135,7 +135,8 @@ class WebView
void navigate (const std::string& url);

/// A callback function which can be passed to bind().
using CallbackFn = std::function<choc::value::Value(const choc::value::ValueView& args)>;
using ReplyFn = std::function<void(choc::value::Value, std::string)>;
using CallbackFn = std::function<void(const choc::value::ValueView& args, ReplyFn&& reply)>;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking thought: I wonder if it's worth supporting both synchronous and async bind() calls. If this were to get upstreamed I think that would be necessary. Maybe have a separate bindWithAsyncReply() method.

That would make the implementation a little more complex, but you should be able to do something like:

// Pseudocode
using CallbackFn = std::function<choc::value::Value(const choc::value::ValueView& args)>;
using AsyncCallbackFn = std::function<void(const choc::value::ValueView& args, ReplyFn&& reply)>;
// ...
unordered_map<string, variant<CallbackFn, AsyncCallbackFn>> bindings;
// ...
invokeBinding() {
   if (holds_alternative<CallbackFn>(b)) {
       doSynchronousCallback();
    } else {
        doAsyncCallback();
    }
}

Copy link

@steve-mackinnon steve-mackinnon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So pumped about this! really solid solution 🔥

@nick-thompson nick-thompson merged commit f5491e1 into main Mar 22, 2024
@nick-thompson nick-thompson deleted the nick/async-bind branch March 22, 2024 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants