Calling into the Page
Call page functions, evaluate scripts, and receive typed results directly in C++.
On this page
Your C++ code can evaluate arbitrary strings of JavaScript and call functions defined on a page (with type-converted results).
Example HTML
The examples in this guide use this HTML snippet:
<html>
<head>
<script>
var score = 42;
function ShowMessage(message) {
if (!message) throw new Error("empty message");
document.getElementById('msg').innerHTML = message;
}
function computeTotal(a, b) {
return a + b;
}
</script>
</head>
<body>
<div id="msg"></div>
</body>
</html>
Getting the Page's Context
Every call into a page goes through its js::Context. You can get it from a View via LoadListener::OnDOMReady():
// Inherited from LoadListener::OnDOMReady:
void MyApp::OnDOMReady(View* caller, uint64_t frame_id, bool is_main_frame,
const String& url) {
if (!is_main_frame)
return;
// Get the context of the View's main frame.
js::Context ctx(caller);
}
π When to Get the Context
Use
OnDOMReady()for calls that need the page's DOM or its scripts. If native code needs to set up state before the page's own scripts run, get the context inOnWindowObjectReady()insteadβ it fires beforeOnDOMReady(). See Handling View Events for details on both callbacks.
One Context per Navigation
Each page gets its own context. After every navigation you'll need to get a new one.
The old context and every value from it are then no longer valid. Anything you do with them fails safely instead of crashing.
π§ Stay on the Renderer's Thread
Every call into the page must run on the Renderer's thread.
Calling a Function
Index the context with the function's name and call it:
ctx["ShowMessage"]("Howdy!");
Indexing ctx reads a property of the page's global object (ie, window).
Getting Results
Calls to JavaScript functions return js::Result which can be converted to a C++ type. (See Async Callbacks to wait for a function that returns a Promise.)
With a Fallback
Use js::Or() to convert a value or a call's result to a C++ type with a fallback:
double score = js::Or(ctx["score"], 0.0);
double total = js::Or(ctx["computeTotal"](3, 4), 0.0);
You get the fallback if the property is missing, the call fails, or the value isn't already a number (conversion is strict and never coerces).
Type-Checked Call Results
Use Invoke<T>() when you want to call a JavaScript function and enforce a specific C++ return type. It returns a js::Result that holds either the converted value or a js::Error:
js::Result<double> total = ctx["computeTotal"].Invoke<double>(3, 4);
if (total)
UseTotal(*total);
else if (total.error().is_page_gone())
return; // the page is gone (nothing to report)
else
Log(total.error().message()); // it threw or didn't return a number
π Ignored Exceptions Are Never Lost
All JavaScript API errors or exceptions encountered are written to
Loggerwhen developer mode is active (see Developer Mode and Diagnostics).
Keeping a Function for Later
Store a function in a js::Value to call it later:
js::Value show = ctx["ShowMessage"];
// Later:
if (show.IsCallable())
show("Howdy again!");
π The Value of
thisCalling a stored function sets
thisto the global object. Useshow.InvokeOn(object, args...)to call it as a method of some object instead.
Running a Script
Evaluating a Script
Call ctx.Evaluate() to run a script on the page:
js::Result<js::Value> result = ctx.Evaluate("score * 2"); // holds 84
The result holds the script's value as a js::Value (or the error if the script threw).
Converting the Result
Use Evaluate<T>() to convert the script's value to a C++ type. Wrap it in js::Or() for a fallback:
double doubled = js::Or(ctx.Evaluate<double>("score * 2"), 0.0);
Evaluating Without a Context
Call View::EvaluateScript() on the View when a string is all you need:
String title = view->EvaluateScript("document.title");
The result is converted to a string (undefined becomes "undefined"). The optional second argument (a String*) receives the message if the script throws.
Handing the Page a Callback
ctx.MakeFunction() creates a JavaScript function that runs your C++ callback:
js::Value cb = ctx.MakeFunction("onTick", [](double dt) { /* ... */ });
ctx["registerTick"](cb);
The page can keep the function and call it whenever it likes:
let tick = null;
function registerTick(cb) { tick = cb; }
// Later: runs the C++ callback with dt = 16.7.
tick(16.7);
Your C++ callback never runs if the page passes an argument of the wrong type (eg, a string for dt). The page gets a TypeError instead.
The callback must be synchronous (it returns a value or a js::Result).
π§ Callback Lifetime
The callback is destroyed on the Renderer's thread after the page's function is garbage collected. Use a
js::APIbinding instead for a function that must survive navigation or run asynchronously (see Extending JavaScript with Native API).