Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

syscall/js 包详解

概述

syscall/js 包在使用 js/wasm 架构时提供对 WebAssembly 主机环境的访问。其 API 基于 JavaScript 语义。

核心功能

  • JavaScript 对象访问和操作
  • Go 与 JavaScript 函数互调用
  • 类型转换(Go ↔ JavaScript)
  • DOM 事件处理
  • WebAssembly 宿主环境交互

重要说明

  • ⚠️ 实验性:此包是 EXPERIMENTAL,可能发生变化
  • ⚠️ 平台限制:仅适用于 js/wasm 架构(GOOS=js, GOARCH=wasm)
  • ⚠️ 不兼容保证:不受 Go 兼容性承诺保护
  • ⚠️ 资源管理:Func 必须调用 Release 释放资源

包导入

import "syscall/js"

常量

Type 类型常量

const (
    TypeUndefined Type = iota // undefined
    TypeNull                  // null
    TypeBoolean               // boolean
    TypeNumber                // number
    TypeString                // string
    TypeSymbol                // symbol
    TypeObject                // object
    TypeFunction              // function
)

功能: 表示 JavaScript 值的类型。

类型详解(按 A-Z 分类)

E

Error

type Error struct {
    Value
}

功能: 包装 JavaScript 错误。

方法

  • Error() string - 实现 error 接口

示例

package main

import (
    "syscall/js"
)

func main() {
    // 触发 JavaScript 错误
    result, err := js.Global().Call("nonExistentFunction")
    if err != nil {
        jsErr, ok := err.(js.Error)
        if ok {
            println("JS 错误:", jsErr.Error())
        }
    }
    
    _ = result
}

F

Func

type Func struct {
    Value
}

功能: 包装 Go 函数供 JavaScript 调用。

重要说明

  • 从 JavaScript 调用包装的 Go 函数会暂停事件循环并启动新的 goroutine
  • 在 Go 调用 JavaScript 期间触发的其他包装函数在同一 goroutine 上执行
  • 如果一个包装函数阻塞,JavaScript 事件循环会被阻塞直到该函数返回
  • 调用异步 JavaScript API(如 fetch)会导致死锁
  • 阻塞函数应显式启动新的 goroutine
  • 必须调用 Release 释放资源

方法

  • Release() - 释放资源

示例

package main

import (
    "syscall/js"
)

func main() {
    // 创建 Go 函数供 JS 调用
    callback := js.FuncOf(func(this js.Value, args []js.Value) any {
        println("JS 调用了 Go 函数")
        if len(args) > 0 {
            println("参数:", args[0].String())
        }
        return nil
    })
    
    // 设置到全局
    js.Global().Set("goCallback", callback)
    
    // 使用完成后释放
    defer callback.Release()
    
    // 防止程序退出
    select {}
}

FuncOf

func FuncOf(fn func(this Value, args []Value) any) Func

功能: 返回一个供 JavaScript 使用的函数。

参数

  • fn func(this Value, args []Value) any - Go 函数
    • this - JavaScript 的 this 关键字
    • args - 调用参数
    • 返回值通过 ValueOf 映射回 JavaScript

返回值

  • Func - 包装后的函数

注意

  • 必须调用 Release 释放资源

示例

package main

import (
    "syscall/js"
)

func add(this js.Value, args []js.Value) any {
    if len(args) != 2 {
        return js.Undefined()
    }
    a := args[0].Int()
    b := args[1].Int()
    return a + b
}

func main() {
    addFunc := js.FuncOf(add)
    js.Global().Set("add", addFunc)
    defer addFunc.Release()
    
    select {}
}

T

Type

type Type uint8

功能: 表示 JavaScript 值的类型。

方法

  • String() string - 返回类型的字符串表示

示例

package main

import (
    "fmt"
    "syscall/js"
)

func main() {
    v := js.Global().Get("console")
    t := v.Type()
    fmt.Println("类型:", t)       // object
    fmt.Println("类型字符串:", t.String())
}

V

Value

type Value struct {
    // 包含过滤或未导出的字段
}

功能: 表示 JavaScript 值。零值是 JavaScript 的 “undefined”。

重要说明

  • 值可以使用 Equal 方法检查相等性
  • 不能直接用 == 比较

方法

  • Bool() bool - 转换为 bool
  • Call(m string, args ...any) Value - 调用方法
  • Delete(p string) - 删除属性
  • Equal(w Value) bool - 检查相等性
  • Float() float64 - 转换为 float64
  • Get(p string) Value - 获取属性
  • Index(i int) Value - 获取索引
  • InstanceOf(t Value) bool - instanceof 检查
  • Int() int - 转换为 int
  • Invoke(args ...any) Value - 调用函数
  • IsNaN() bool - 检查 NaN
  • IsNull() bool - 检查 null
  • IsUndefined() bool - 检查 undefined
  • Length() int - 获取 length 属性
  • New(args ...any) Value - 使用 new 运算符
  • Set(p string, x any) - 设置属性
  • SetIndex(i int, x any) - 设置索引
  • String() string - 转换为字符串
  • Truthy() bool - 检查真值
  • Type() Type - 获取类型

示例

package main

import (
    "syscall/js"
)

func main() {
    // 获取全局对象
    global := js.Global()
    
    // 获取 window 对象
    window := global.Get("window")
    
    // 获取属性
    console := global.Get("console")
    
    // 调用方法
    console.Call("log", "Hello from Go!")
    
    // 设置属性
    global.Set("myVar", 42)
    
    // 调用函数
    alert := global.Get("alert")
    alert.Invoke("Alert from Go!")
}

ValueOf

func ValueOf(x any) Value

功能: 将 Go 值转换为 JavaScript 值。

参数

  • x any - Go 值

返回值

  • Value - JavaScript 值

类型映射

GoJavaScript
js.Value[its value]
js.Funcfunction
nilnull
boolboolean
integers and floatsnumber
stringstring
[]interface{}new array
map[string]interface{}new object

注意

  • 如果 x 不是预期类型会 panic

示例

package main

import (
    "syscall/js"
)

func main() {
    // 基本类型
    js.Global().Set("num", js.ValueOf(42))
    js.Global().Set("str", js.ValueOf("hello"))
    js.Global().Set("bool", js.ValueOf(true))
    
    // 数组
    arr := []interface{}{1, 2, 3}
    js.Global().Set("myArray", js.ValueOf(arr))
    
    // 对象
    obj := map[string]interface{}{
        "name": "Alice",
        "age":  25,
    }
    js.Global().Set("myObject", js.ValueOf(obj))
}

Value.Bool

func (v Value) Bool() bool

功能: 将值 v 作为 bool 返回。

注意

  • 如果 v 不是 JavaScript boolean 会 panic

示例

b := js.Global().Get("someBool").Bool()

Value.Call

func (v Value) Call(m string, args ...any) Value

功能: 调用值 v 的方法 m。

参数

  • m string - 方法名
  • args ...any - 参数

返回值

  • Value - 返回值

注意

  • 如果 v 没有方法 m 会 panic
  • 参数根据 ValueOf 映射到 JavaScript

示例

// console.log("Hello")
js.Global().Get("console").Call("log", "Hello")

// array.push(1)
array.Get("array").Call("push", 1)

Value.Delete

func (v Value) Delete(p string)

功能: 删除值 v 的 JavaScript 属性 p。

参数

  • p string - 属性名

注意

  • 如果 v 不是 JavaScript object 会 panic

Value.Equal

func (v Value) Equal(w Value) bool

功能: 根据 JavaScript 的 === 运算符报告 v 和 w 是否相等。

示例

v1 := js.Global().Get("obj1")
v2 := js.Global().Get("obj2")
if v1.Equal(v2) {
    println("相等")
}

Value.Float

func (v Value) Float() float64

功能: 将值 v 作为 float64 返回。

注意

  • 如果 v 不是 JavaScript number 会 panic

Value.Get

func (v Value) Get(p string) Value

功能: 返回值 v 的 JavaScript 属性 p。

参数

  • p string - 属性名

返回值

  • Value - 属性值

注意

  • 如果 v 不是 JavaScript object 会 panic

示例

// 获取 document
doc := js.Global().Get("document")

// 获取 window.location
location := js.Global().Get("window").Get("location")

// 获取嵌套属性
hostname := location.Get("hostname")

Value.Index

func (v Value) Index(i int) Value

功能: 返回值 v 的 JavaScript 索引 i。

参数

  • i int - 索引

返回值

  • Value - 索引处的值

注意

  • 如果 v 不是 JavaScript object 会 panic

示例

array := js.Global().Get("myArray")
first := array.Index(0)
second := array.Index(1)

Value.InstanceOf

func (v Value) InstanceOf(t Value) bool

功能: 根据 JavaScript 的 instanceof 运算符报告 v 是否是 t 的实例。

示例

array := js.Global().Get("myArray")
arrayConstructor := js.Global().Get("Array")
if array.InstanceOf(arrayConstructor) {
    println("是 Array 实例")
}

Value.Int

func (v Value) Int() int

功能: 将值 v 截断为 int 返回。

注意

  • 如果 v 不是 JavaScript number 会 panic

Value.Invoke

func (v Value) Invoke(args ...any) Value

功能: 调用值 v(作为函数)。

参数

  • args ...any - 参数

返回值

  • Value - 返回值

注意

  • 如果 v 不是 JavaScript 函数会 panic
  • 参数根据 ValueOf 映射到 JavaScript

示例

// 调用全局函数
parseInt := js.Global().Get("parseInt")
result := parseInt.Invoke("42")
println(result.Int()) // 42

// 调用 setTimeout
setTimeout := js.Global().Get("setTimeout")
setTimeout.Invoke(js.FuncOf(func(this js.Value, args []js.Value) any {
    println("Timeout!")
    return nil
}), 1000)

Value.IsNaN

func (v Value) IsNaN() bool

功能: 报告 v 是否是 JavaScript 值 “NaN”。

Value.IsNull

func (v Value) IsNull() bool

功能: 报告 v 是否是 JavaScript 值 “null”。

Value.IsUndefined

func (v Value) IsUndefined() bool

功能: 报告 v 是否是 JavaScript 值 “undefined”。

Value.Length

func (v Value) Length() int

功能: 返回 v 的 JavaScript 属性 “length”。

注意

  • 如果 v 不是 JavaScript object 会 panic

示例

array := js.Global().Get("myArray")
length := array.Length()
println("数组长度:", length)

str := js.Global().Get("myString")
length = str.Length()
println("字符串长度:", length)

Value.New

func (v Value) New(args ...any) Value

功能: 使用 JavaScript 的 “new” 运算符。

参数

  • args ...any - 构造函数参数

返回值

  • Value - 新创建的对象

注意

  • 如果 v 不是 JavaScript 函数会 panic
  • 参数根据 ValueOf 映射到 JavaScript

示例

// new Date()
dateConstructor := js.Global().Get("Date")
date := dateConstructor.New()

// new Array(10)
arrayConstructor := js.Global().Get("Array")
array := arrayConstructor.New(10)

Value.Set

func (v Value) Set(p string, x any)

功能: 将值 v 的 JavaScript 属性 p 设置为 ValueOf(x)。

参数

  • p string - 属性名
  • x any - 属性值

注意

  • 如果 v 不是 JavaScript object 会 panic

示例

// 设置全局变量
js.Global().Set("myVar", 42)
js.Global().Set("myString", "hello")

// 设置对象属性
obj := js.Global().Get("myObject")
obj.Set("name", "Alice")
obj.Set("age", 25)

Value.SetIndex

func (v Value) SetIndex(i int, x any)

功能: 将值 v 的 JavaScript 索引 i 设置为 ValueOf(x)。

参数

  • i int - 索引
  • x any - 值

注意

  • 如果 v 不是 JavaScript object 会 panic

示例

array := js.Global().Get("myArray")
array.SetIndex(0, 1)
array.SetIndex(1, 2)
array.SetIndex(2, 3)

Value.String

func (v Value) String() string

功能: 将值 v 作为字符串返回。

注意

  • 如果 v 的 Type 不是 TypeString 不会 panic
  • 返回形式为 “” 或 “<T: V>” 的字符串

示例

str := js.Global().Get("myString").String()
println("字符串:", str)

// 非字符串类型
num := js.Global().Get("myNumber")
str = num.String() // 返回值的字符串表示

Value.Truthy

func (v Value) Truthy() bool

功能: 报告 v 在 JavaScript 布尔上下文中是否为真。

JavaScript 假值

  • undefined
  • null
  • false
  • 0
  • NaN
  • “”(空字符串)

示例

v := js.Global().Get("someValue")
if v.Truthy() {
    println("真值")
} else {
    println("假值")
}

Value.Type

func (v Value) Type() Type

功能: 返回值 v 的 JavaScript 类型。

返回值

  • Type - JavaScript 类型

注意

  • 类似于 JavaScript 的 typeof 运算符
  • 对 null 返回 TypeNull 而不是 TypeObject

ValueError

type ValueError struct {
    Method string
    Type   Type
}

功能: 当在 Value 上调用不支持的方法时发生。

方法

  • Error() string - 实现 error 接口

函数详解(按 A-Z 分类)

C

CopyBytesToGo

func CopyBytesToGo(dst []byte, src Value) int

功能: 从 src 复制字节到 dst。

参数

  • dst []byte - 目标字节切片
  • src Value - JavaScript Uint8Array 或 Uint8ClampedArray

返回值

  • int - 复制的字节数(src 和 dst 长度的最小值)

注意

  • 如果 src 不是 Uint8Array 或 Uint8ClampedArray 会 panic

示例

package main

import (
    "syscall/js"
)

func main() {
    // 从 JavaScript 获取 Uint8Array
    jsArray := js.Global().Get("myUint8Array")
    
    // 创建 Go 字节切片
    goBytes := make([]byte, jsArray.Length())
    
    // 复制数据
    n := js.CopyBytesToGo(goBytes, jsArray)
    println("复制了", n, "字节")
}

CopyBytesToJS

func CopyBytesToJS(dst Value, src []byte) int

功能: 从 src 复制字节到 dst。

参数

  • dst Value - JavaScript Uint8Array 或 Uint8ClampedArray
  • src []byte - 源字节切片

返回值

  • int - 复制的字节数(src 和 dst 长度的最小值)

注意

  • 如果 dst 不是 Uint8Array 或 Uint8ClampedArray 会 panic

示例

package main

import (
    "syscall/js"
)

func main() {
    // 创建 JavaScript Uint8Array
    arrayConstructor := js.Global().Get("Uint8Array")
    jsArray := arrayConstructor.New(10)
    
    // Go 字节数据
    goBytes := []byte{1, 2, 3, 4, 5}
    
    // 复制数据到 JS
    n := js.CopyBytesToJS(jsArray, goBytes)
    println("复制了", n, "字节")
}

G

Global

func Global() Value

功能: 返回 JavaScript 全局对象,通常是 “window”(浏览器)或 “global”(Node.js)。

返回值

  • Value - 全局对象

示例

package main

import (
    "syscall/js"
)

func main() {
    global := js.Global()
    
    // 访问全局属性
    console := global.Get("console")
    document := global.Get("document")
    
    // 调用全局方法
    console.Call("log", "Hello from Go!")
}

N

Null

func Null() Value

功能: 返回 JavaScript 值 “null”。

返回值

  • Value - null 值

示例

js.Global().Set("myNull", js.Null())

U

Undefined

func Undefined() Value

功能: 返回 JavaScript 值 “undefined”。

返回值

  • Value - undefined 值

示例

js.Global().Set("myUndefined", js.Undefined())

典型示例

示例 1:基本 JavaScript 交互

package main

import (
    "syscall/js"
)

func main() {
    // 获取全局对象
    global := js.Global()
    
    // 获取 console 并调用 log
    console := global.Get("console")
    console.Call("log", "Hello from WebAssembly!")
    
    // 设置全局变量
    global.Set("goVar", 42)
    global.Set("goString", "Hello")
    
    // 获取属性
    location := global.Get("location")
    hostname := location.Get("hostname")
    console.Call("log", "Hostname:", hostname)
}

示例 2:Go 函数供 JavaScript 调用

package main

import (
    "syscall/js"
)

func add(this js.Value, args []js.Value) any {
    if len(args) != 2 {
        return js.Undefined()
    }
    a := args[0].Int()
    b := args[1].Int()
    return a + b
}

func greet(this js.Value, args []js.Value) any {
    if len(args) == 0 {
        return "Hello!"
    }
    name := args[0].String()
    return "Hello, " + name + "!"
}

func main() {
    // 导出函数到 JavaScript
    js.Global().Set("add", js.FuncOf(add))
    js.Global().Set("greet", js.FuncOf(greet))
    
    console := js.Global().Get("console")
    console.Call("log", "Go functions exported!")
    
    // 防止程序退出
    select {}
}

JavaScript 使用

console.log(add(10, 20)); // 30
console.log(greet("Alice")); // "Hello, Alice!"

示例 3:操作 DOM

package main

import (
    "syscall/js"
)

func main() {
    document := js.Global().Get("document")
    
    // 获取元素
    body := document.Get("body")
    
    // 创建元素
    h1 := document.Call("createElement", "h1")
    h1.Call("setAttribute", "id", "go-title")
    h1.Set("innerHTML", "Hello from Go!")
    
    // 添加到页面
    body.Call("appendChild", h1)
    
    // 修改样式
    style := h1.Get("style")
    style.Set("color", "blue")
    style.Set("fontSize", "24px")
    
    // 添加点击事件
    h1.Set("onclick", js.FuncOf(func(this js.Value, args []js.Value) any {
        js.Global().Get("console").Call("log", "Title clicked!")
        return nil
    }))
    
    select {}
}

示例 4:处理异步操作

package main

import (
    "syscall/js"
)

func handlePromise(this js.Value, args []js.Value) any {
    if len(args) == 0 {
        return js.Undefined()
    }
    
    promise := args[0]
    
    // 创建 then 回调
    thenCallback := js.FuncOf(func(this js.Value, args []js.Value) any {
        js.Global().Get("console").Call("log", "Promise resolved:", args[0])
        return nil
    })
    
    // 创建 catch 回调
    catchCallback := js.FuncOf(func(this js.Value, args []js.Value) any {
        js.Global().Get("console").Call("log", "Promise rejected:", args[0])
        return nil
    })
    
    // 链式调用
    promise.Call("then", thenCallback).Call("catch", catchCallback)
    
    return nil
}

func main() {
    js.Global().Set("handlePromise", js.FuncOf(handlePromise))
    
    // JavaScript 可以这样调用:
    // handlePromise(fetch('/api/data'))
    
    select {}
}

示例 5:字节数据转换

package main

import (
    "syscall/js"
)

func main() {
    // Go 字节转 JavaScript Uint8Array
    goData := []byte{1, 2, 3, 4, 5}
    
    arrayConstructor := js.Global().Get("Uint8Array")
    jsArray := arrayConstructor.New(len(goData))
    
    // 复制到 JS
    js.CopyBytesToJS(jsArray, goData)
    js.Global().Set("myArray", jsArray)
    
    // JavaScript Uint8Array 转 Go
    jsArray2 := js.Global().Get("myArray")
    goBytes := make([]byte, jsArray2.Length())
    js.CopyBytesToGo(goBytes, jsArray2)
    
    console := js.Global().Get("console")
    console.Call("log", "Go bytes:", goBytes)
    
    select {}
}

示例 6:事件处理

package main

import (
    "syscall/js"
)

func main() {
    document := js.Global().Get("document")
    
    // 获取按钮
    button := document.Call("getElementById", "myButton")
    
    // 添加点击事件
    clickHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
        js.Global().Get("console").Call("log", "Button clicked!")
        
        // 阻止默认行为
        event := args[0]
        event.Call("preventDefault")
        
        return nil
    })
    
    button.Call("addEventListener", "click", clickHandler)
    
    // 添加鼠标悬停事件
    mouseHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
        js.Global().Get("console").Call("log", "Mouse over!")
        return nil
    })
    
    button.Call("addEventListener", "mouseover", mouseHandler)
    
    select {}
}

示例 7:调用 JavaScript 库

package main

import (
    "syscall/js"
)

func main() {
    // 假设页面加载了 jQuery
    $ := js.Global().Get("$")
    
    // 使用 jQuery
    $("body").Call("css", "background-color", "lightblue")
    
    // 添加元素
    $("<h1>").
        Call("text", "jQuery from Go").
        Call("appendTo", "body")
    
    // 添加点击事件
    $("button").Call("on", "click", js.FuncOf(func(this js.Value, args []js.Value) any {
        js.Global().Get("console").Call("log", "Button clicked via jQuery")
        return nil
    }))
    
    select {}
}

示例 8:与 JavaScript 双向通信

package main

import (
    "syscall/js"
)

// 导出到 JavaScript 的函数
func jsCallback(this js.Value, args []js.Value) any {
    if len(args) == 0 {
        return nil
    }
    
    message := args[0].String()
    js.Global().Get("console").Call("log", "JS 调用 Go:", message)
    
    // 返回值给 JavaScript
    return map[string]interface{}{
        "status":  "success",
        "message": "处理完成:" + message,
    }
}

func main() {
    // 导出函数
    js.Global().Set("goCallback", js.FuncOf(jsCallback))
    
    // 调用 JavaScript 函数
    jsCode := `
        // 调用 Go 函数
        const result = goCallback("Hello from JS");
        console.log("Go 返回:", result);
    `
    js.Global().Call("eval", jsCode)
    
    select {}
}

最佳实践

1. 正确管理资源

// ✅ 推荐:使用 defer 释放
callback := js.FuncOf(myFunc)
js.Global().Set("callback", callback)
defer callback.Release()

// ❌ 不推荐:忘记释放
callback := js.FuncOf(myFunc)
js.Global().Set("callback", callback)
// 资源泄漏

2. 避免阻塞事件循环

// ✅ 推荐:在 goroutine 中执行阻塞操作
js.Global().Set("handler", js.FuncOf(func(this js.Value, args []js.Value) any {
    go func() {
        // 阻塞操作
        time.Sleep(time.Second)
    }()
    return nil
}))

// ❌ 不推荐:直接阻塞
js.Global().Set("handler", js.FuncOf(func(this js.Value, args []js.Value) any {
    time.Sleep(time.Second) // 阻塞事件循环
    return nil
}))

3. 错误处理

// ✅ 推荐:检查错误
result, err := js.Global().Call("someFunction")
if err != nil {
    jsErr, ok := err.(js.Error)
    if ok {
        println("JS 错误:", jsErr.Error())
    }
}

// ❌ 不推荐:忽略错误
result, _ := js.Global().Call("someFunction")

4. 类型安全

// ✅ 推荐:检查类型
v := js.Global().Get("myValue")
if v.Type() == js.TypeString {
    str := v.String()
    // 使用 str
}

// ❌ 不推荐:直接转换可能 panic
str := v.String() // 如果不是字符串会 panic

与其他包配合

与 encoding/json 配合

package main

import (
    "encoding/json"
    "syscall/js"
)

func main() {
    // Go 结构体转 JavaScript 对象
    data := map[string]interface{}{
        "name": "Alice",
        "age":  25,
    }
    
    jsonData, _ := json.Marshal(data)
    var jsObj interface{}
    json.Unmarshal(jsonData, &jsObj)
    
    js.Global().Set("goData", js.ValueOf(jsObj))
    
    // JavaScript 对象转 Go
    jsData := js.Global().Get("jsData")
    // 需要通过回调获取数据
}

与 context 配合

package main

import (
    "context"
    "syscall/js"
)

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    
    // 创建取消按钮
    document := js.Global().Get("document")
    button := document.Call("getElementById", "cancelBtn")
    
    button.Set("onclick", js.FuncOf(func(this js.Value, args []js.Value) any {
        cancel()
        return nil
    }))
    
    // 使用 context
    go func() {
        <-ctx.Done()
        println("操作已取消")
    }()
    
    select {}
}

注意事项

限制

  1. 平台限制

    • 仅适用于 js/wasm 架构
    • 需要 GOOS=js, GOARCH=wasm 编译
  2. 实验性

    • API 可能发生变化
    • 不受 Go 兼容性承诺保护
  3. 事件循环

    • 包装的 Go 函数会阻塞 JavaScript 事件循环
    • 异步操作需要特殊处理
  4. 资源管理

    • Func 必须调用 Release
    • 忘记释放会导致内存泄漏

使用建议

  1. 编译命令

    GOOS=js GOARCH=wasm go build -o main.wasm main.go
    
  2. HTML 模板

    <!DOCTYPE html>
    <script src="wasm_exec.js"></script>
    <script>
        const go = new Go();
        WebAssembly.instantiateStreaming(
            fetch("main.wasm"), go.importObject
        ).then(result => {
            go.run(result.instance);
        });
    </script>
    
  3. 避免的操作

    • 不要在包装函数中调用异步 JS API
    • 不要长时间阻塞
    • 不要忘记 Release

快速参考

类型映射表

GoJavaScript
js.Value[its value]
js.Funcfunction
nilnull
boolboolean
int/floatnumber
stringstring
[]interface{}array
map[string]interface{}object

常用 JavaScript API

// Console
js.Global().Get("console").Call("log", "message")

// DOM
doc := js.Global().Get("document")
elem := doc.Call("getElementById", "id")

// 事件
elem.Call("addEventListener", "click", handler)

// 定时器
js.Global().Call("setTimeout", callback, 1000)
js.Global().Call("setInterval", callback, 1000)

// Fetch (需要 goroutine)
go func() {
    promise := js.Global().Call("fetch", "/api")
    // 处理 promise
}()

方法速查

方法功能
Global()获取全局对象
ValueOf(x)Go 值转 JS
Get(p)获取属性
Set(p, x)设置属性
Call(m, args...)调用方法
Invoke(args...)调用函数
New(args...)new 运算符
Index(i)获取索引
SetIndex(i, x)设置索引
Type()获取类型
Bool()/Int()/Float()/String()类型转换

总结

syscall/js 包提供了 Go 与 JavaScript 互操作的能力。

核心优势

  • ✅ 直接访问 WebAssembly 宿主环境
  • ✅ 完整的 JavaScript API 访问
  • ✅ Go 与 JS 双向通信
  • ✅ 类型自动转换

重要限制

  • ⚠️ 仅适用于 js/wasm 架构
  • ⚠️ 实验性 API,可能变化
  • ⚠️ 需要手动管理资源
  • ⚠️ 可能阻塞事件循环

主要用途

  • WebAssembly 模块开发
  • 浏览器端 Go 代码
  • JavaScript 库封装
  • DOM 操作和事件处理

使用建议

  1. 使用 GOOS=js GOARCH=wasm 编译
  2. 始终调用 Release 释放资源
  3. 避免在包装函数中阻塞
  4. 使用 goroutine 处理异步操作
  5. 检查类型避免 panic

编译示例

GOOS=js GOARCH=wasm go build -o main.wasm main.go