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
});重入死锁
槽 A 内 call("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++ |
无需手引脚本。资源打包模式下随页面注入;远程地址模式下由注入逻辑处理。
下一步
- 窗口控制:在窗口上挂 Bridge
- WindowTem 模板:省 RPC 样板的糖衣