Skip to content

RPC 通信

Bridge 是 JS 与 C++ 之间的双向 JSON-RPC 通道,每个 Window 自带一个。三种调用模式:注册槽(on)同步调用(call)即发即忘(send)

注册槽:JS → C++

on(name, fn) 注册一个槽函数,参数从 JSON 反序列化,返回值序列化回 JS。

cpp
win->on("add", [](int a, int b) { return a + b; });

// 返回对象 → JS 拿到对象
win->on("fetchUser", [](int id) {
    return json{{"id", id}, {"name", "alice"}};
});

// 返回 future → JS await 一个 Promise(异步)
win->on("fetchData", [](int n) {
    std::promise<json> p;
    p.set_value(json{{"doubled", n * 2}});
    return p.get_future();
});

前端调用:

js
const sum  = await bridge.call('add', 2, 3);          // → 5
const user = await bridge.call('fetchUser', 42);      // → {id:42,name:"alice"}
const data = await bridge.call('fetchData', 7);       // → {doubled:14}(异步)

返回 std::future<T> 时,JS 端自动拿到一个 Promise,C++ 嵌套消息泵等其 resolve。

同步调用:C++ → JS

call<T>(name, args...) 同步调 JS 端注册的槽,阻塞等返回值。

cpp
// JS: bridge.on('greet', n => 'hello ' + n)
std::string reply = win->call<std::string>("greet", "world");  // → "hello world"

特性:

  • 嵌套消息泵:等待期间继续派发 UI 消息,UI 不卡死
  • 超时:默认 300s(WindowTem 构造可配),超时抛 std::runtime_error
  • 重入死锁检测:若槽 A 内部又 call(A),直接抛异常而非死锁
cpp
win->on("triggerGreet", [w = win.get()]() -> std::string {
    return w->call<std::string>("greet", "world");   // 合法:不同 channel
});

重入死锁

Acall("A") 会触发死锁检测抛异常。这是有意设计——嵌套泵重入同名通道必然死锁,框架提前拒绝。

即发即忘:send

send(name, args...) 不等返回,用于事件通知 / 广播。

cpp
win->send("dataReady", payload);          // 单窗口通知
app.broadcast("tick", counter);           // 全窗口广播

JS 监听:

js
bridge.on('dataReady', data => render(data));
bridge.on('tick', c => setCount(c));

envelope 信封

所有跨界调用走固定 JSON 信封:

json
{ "id": 1, "channel": "add", "args": [2, 3] }          // 请求
{ "id": 1, "result": 5 }                                 // 成功回复
{ "id": 1, "error": "..." }                              // 失败回复

参数以 JSON 数组传递,C++ 端 args tuple 按声明类型反序列化。类型不匹配会抛异常,JS 端 Promise reject。

executor 线程

槽函数默认跑在 Bridge executor(Worker 线程池)。耗时任务直接写,在槽里手动起线程又 join 回来——executor 就是干这个的。

cpp
win->on("heavyWork", [](std::string path) {
    // 在 worker 线程跑,不阻塞 UI
    return readBigFile(path);
});

若槽内要操作窗口 / HWND,回到 UI 线程(用 App 投递)。

前端 runtime

页面加载时 runtime.js 自动注入,挂 window.bridge。API:

方法说明
bridge.call(name, ...args)调 C++ 槽,返 Promise
bridge.on(name, fn)注册 JS 槽供 C++ 调
bridge.send(name, ...args)即发即忘通知 C++

无需手引脚本。资源打包模式下随页面注入;远程地址模式下由注入逻辑处理。

下一步