Go-前端桥接
直接的 Go-JavaScript 通信
Section titled “直接的 Go-JavaScript 通信”Wails 提供了 Go 与 JavaScript 之间的直接内存桥接,实现了无缝通信,无需 HTTP 开销、进程边界或序列化瓶颈。
关键洞察: 没有 HTTP,没有 IPC,没有进程边界。只有直接函数调用和类型安全。
工作原理:逐步详解
Section titled “工作原理:逐步详解”1. 服务注册(启动时)
Section titled “1. 服务注册(启动时)”当应用程序启动时,Wails 会扫描你的服务:
type GreetService struct { prefix string}
func (g *GreetService) Greet(name string) string { return g.prefix + name + "!"}
func (g *GreetService) Add(a, b int) int { return a + b}
// Register serviceapp := application.New(application.Options{ Services: []application.Service{ application.NewService(&GreetService{prefix: "Hello, "}), },})Wails 执行的操作:
- 扫描结构体以查找导出的方法
- 提取类型信息(参数、返回类型)
- 构建注册表,将方法名映射到函数
- 生成带有完整类型定义的 TypeScript 绑定
2. 绑定生成(构建时)
Section titled “2. 绑定生成(构建时)”Wails 自动生成 TypeScript 绑定:
export function Greet(name: string): Promise<string>export function Add(a: number, b: number): Promise<number>类型映射:
| Go 类型 | TypeScript 类型 |
|---|---|
string | string |
int, int32, int64 | number |
float32, float64 | number |
bool | boolean |
[]T | T[] |
map[string]T | Record<string, T> |
struct | interface |
time.Time | Date |
error | Exception (thrown) |
3. 前端调用(运行时)
Section titled “3. 前端调用(运行时)”开发者从 JavaScript 调用 Go 方法:
import { Greet, Add } from './bindings/GreetService'
// Call Go from JavaScriptconst greeting = await Greet("World")console.log(greeting) // "Hello, World!"
const sum = await Add(5, 3)console.log(sum) // 8发生的过程:
- 调用绑定函数 -
Greet("World") - 创建消息 -
{ service: "GreetService", method: "Greet", args: ["World"] } - 发送到桥接 - 通过 WebView 的 JavaScript 桥接
- 返回 Promise - 等待响应
4. 桥接处理(运行时)
Section titled “4. 桥接处理(运行时)”桥接接收消息并处理它:
安全性: 只有注册的服务和导出的方法可被调用。
5. Go 执行(运行时)
Section titled “5. Go 执行(运行时)”Go 方法执行:
func (g *GreetService) Greet(name string) string { // This runs in Go return g.prefix + name + "!"}执行上下文:
- 在 goroutine 中运行(非阻塞)
- 可以访问 所有 Go 功能(文件系统、网络、数据库)
- 可以自由调用 其他 Go 代码
- 返回结果或错误
6. 响应(运行时)
Section titled “6. 响应(运行时)”结果发送回 JavaScript:
// Promise resolves with resultconst greeting = await Greet("World")// greeting = "Hello, World!"错误处理:
func (g *GreetService) Divide(a, b float64) (float64, error) { if b == 0 { return 0, errors.New("division by zero") } return a / b, nil}try { const result = await Divide(10, 0)} catch (error) { console.error("Go error:", error) // "division by zero"}典型调用开销: <1ms
Frontend Call → Bridge → Go Execution → Bridge → Frontend Response ↓ ↓ ↓ ↓ ↓ <0.1ms <0.1ms [varies] <0.1ms <0.1ms与替代方案对比:
- HTTP/REST: 5-50ms(网络栈、序列化)
- IPC: 1-10ms(进程边界、编组)
- Wails 桥接: <1ms(内存中、直接调用)
每次调用开销: ~1KB(消息缓冲区)
零拷贝优化: 大数据(>1MB)在可能时使用共享内存。
调用是并发的:
- 每个调用在其自己的 goroutine 中运行
- 多个调用可以同时执行
- 调用之间无阻塞
// These run concurrentlyconst [result1, result2, result3] = await Promise.all([ SlowOperation1(), SlowOperation2(), SlowOperation3(),])// Gofunc Example( s string, i int, f float64, b bool,) (string, int, float64, bool) { return s, i, f, b}// TypeScript (auto-generated)function Example( s: string, i: number, f: number, b: boolean,): Promise<[string, number, number, boolean]>// Gofunc Sum(numbers []int) int { total := 0 for _, n := range numbers { total += n } return total}// TypeScriptfunction Sum(numbers: number[]): Promise<number>
// Usageconst total = await Sum([1, 2, 3, 4, 5]) // 15// Gofunc GetConfig() map[string]interface{} { return map[string]interface{}{ "theme": "dark", "fontSize": 14, "enabled": true, }}// TypeScriptfunction GetConfig(): Promise<Record<string, any>>
// Usageconst config = await GetConfig()console.log(config.theme) // "dark"// Gotype User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"`}
func GetUser(id int) (*User, error) { return &User{ ID: id, Name: "Alice", }, nil}// TypeScript(自动生成)interface User { id: number name: string email: string}
function GetUser(id: number): Promise<User>
// 用法const user = await GetUser(1)console.log(user.name) // "Alice"JSON 标签: 使用 json: 标签来控制 TypeScript 中的字段名称。