Go-Frontend Bridge
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 Bridge: <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",---
**對橋接器有疑問?** 請在 [Discord](https://discord.gg/JDdSxwjhGf) 提問,或查看 [繫結範例](https://github.com/wailsapp/wails/tree/master/v3/examples/binding)。