跳转到内容

Go-前端桥接

Wails 提供了 Go 与 JavaScript 之间的直接内存桥接,实现了无缝通信,无需 HTTP 开销、进程边界或序列化瓶颈。

Diagram

关键洞察: 没有 HTTP,没有 IPC,没有进程边界。只有直接函数调用类型安全

当应用程序启动时,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 service
app := application.New(application.Options{
Services: []application.Service{
application.NewService(&GreetService{prefix: "Hello, "}),
},
})

Wails 执行的操作:

  1. 扫描结构体以查找导出的方法
  2. 提取类型信息(参数、返回类型)
  3. 构建注册表,将方法名映射到函数
  4. 生成带有完整类型定义的 TypeScript 绑定

Wails 自动生成 TypeScript 绑定:

frontend/bindings/GreetService.ts
export function Greet(name: string): Promise<string>
export function Add(a: number, b: number): Promise<number>

类型映射:

Go 类型TypeScript 类型
stringstring
int, int32, int64number
float32, float64number
boolboolean
[]TT[]
map[string]TRecord<string, T>
structinterface
time.TimeDate
errorException (thrown)

开发者从 JavaScript 调用 Go 方法:

import { Greet, Add } from './bindings/GreetService'
// Call Go from JavaScript
const greeting = await Greet("World")
console.log(greeting) // "Hello, World!"
const sum = await Add(5, 3)
console.log(sum) // 8

发生的过程:

  1. 调用绑定函数 - Greet("World")
  2. 创建消息 - { service: "GreetService", method: "Greet", args: ["World"] }
  3. 发送到桥接 - 通过 WebView 的 JavaScript 桥接
  4. 返回 Promise - 等待响应

桥接接收消息并处理它:

Diagram

安全性: 只有注册的服务和导出的方法可被调用。

Go 方法执行:

func (g *GreetService) Greet(name string) string {
// This runs in Go
return g.prefix + name + "!"
}

执行上下文:

  • goroutine 中运行(非阻塞)
  • 可以访问 所有 Go 功能(文件系统、网络、数据库)
  • 可以自由调用 其他 Go 代码
  • 返回结果或错误

结果发送回 JavaScript:

// Promise resolves with result
const 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
↓ ↓ ↓ ↓ ↓
&lt;0.1ms &lt;0.1ms [varies] &lt;0.1ms &lt;0.1ms

与替代方案对比:

  • HTTP/REST: 5-50ms(网络栈、序列化)
  • IPC: 1-10ms(进程边界、编组)
  • Wails 桥接: <1ms(内存中、直接调用)

每次调用开销: ~1KB(消息缓冲区)

零拷贝优化: 大数据(>1MB)在可能时使用共享内存。

调用是并发的:

  • 每个调用在其自己的 goroutine 中运行
  • 多个调用可以同时执行
  • 调用之间无阻塞
// These run concurrently
const [result1, result2, result3] = await Promise.all([
SlowOperation1(),
SlowOperation2(),
SlowOperation3(),
])
// Go
func 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]>
// Go
func Sum(numbers []int) int {
total := 0
for _, n := range numbers {
total += n
}
return total
}
// TypeScript
function Sum(numbers: number[]): Promise<number>
// Usage
const total = await Sum([1, 2, 3, 4, 5]) // 15
// Go
func GetConfig() map[string]interface{} {
return map[string]interface{}{
"theme": "dark",
"fontSize": 14,
"enabled": true,
}
}
// TypeScript
function GetConfig(): Promise<Record<string, any>>
// Usage
const config = await GetConfig()
console.log(config.theme) // "dark"
// Go
type 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 中的字段名称。

有关桥接的问题? 请在 Discord 提问或查看 绑定示例