You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TinyGo编译WASM如何返回JS可识别的对象/数组等返回值

你拿到的102752这类数字是WASM线性内存的指针地址,不是实际返回值。WASM核心规范仅支持i32、i64、f32、f64四种数字类型作为函数入参与返回值,所有复杂类型(map、数组、字符串、结构体)都存储在WASM独占的线性内存中,JS无法直接读取,必须手动完成内存交互。

以下是两种可直接落地的实现方案:

方案1:JSON序列化交互(最通用,支持map/数组/结构体)

该方案不需要手动解析Go复杂类型的内部内存布局,兼容性最好,适配所有可序列化的返回类型。

Go侧代码调整

不要直接返回map,将返回值序列化为JSON字节流,写入JS传入的预分配内存中:

package main

import (
	"encoding/json"
	"unsafe"
)

// 提前定义返回结构,比map[string]interface{}性能更稳定
// 如果要返回数组,直接把res换成[]int{60, 1}即可
type Result struct {
	Key    int `json:"key"`
	Remove int `json:"remove"`
}

//export onInput
// 入参:JS预分配的内存指针、内存缓冲区大小
// 返回值:写入内存的字节长度,-1代表缓冲区不足
func onInput(bufPtr uintptr, bufSize int) int {
	res := Result{
		Key:    60,
		Remove: 1,
	}
	data, _ := json.Marshal(res)
	if len(data) > bufSize {
		return -1
	}
	// 将指针转为字节切片,写入JSON数据
	buf := unsafe.Slice((*byte)(unsafe.Pointer(bufPtr)), bufSize)
	copy(buf, data)
	return len(data)
}

func main() {}

编译命令保持原有逻辑即可:

tinygo build -o main.wasm -target wasm ./main.go

JS侧调用逻辑

JS侧先通过TinyGo默认导出的malloc分配WASM内存,调用函数后从内存中读取字节流,解析为JS对象:

const { memory, malloc, free, onInput } = wasm.instance.exports;

// 分配1KB缓冲区足够存储当前小对象,大返回值可按需调整大小
const BUF_SIZE = 1024;
const bufPtr = malloc(BUF_SIZE);

// 调用导出函数,获取写入数据长度
const dataLen = onInput(bufPtr, BUF_SIZE);
if (dataLen === -1) {
	throw new Error("缓冲区不足,无法存储返回值");
}

// 从WASM内存读取JSON字符串并解析
const memView = new Uint8Array(memory.buffer, bufPtr, dataLen);
const result = JSON.parse(new TextDecoder().decode(memView));
console.log(result); // {key: 60, remove: 1},序列化数组时此处输出[60, 1]

// 释放分配的内存,避免泄漏
free(bufPtr);

方案2:固定结构直接传值(适合简单固定结构,性能更高)

如果返回值是固定数量的数值类型,不需要序列化开销,可以通过传入多个指针存储返回值:

Go侧代码

package main

//export onInput
// 传入两个int类型指针,分别存储两个返回值
func onInput(keyPtr *int, removePtr *int) {
	*keyPtr = 60
	*removePtr = 1
}

func main() {}

JS侧代码

const { memory, malloc, free, onInput } = wasm.instance.exports;
// TinyGo wasm32目标下int占4字节,分别为两个返回值分配内存
const keyPtr = malloc(4);
const removePtr = malloc(4);

onInput(keyPtr, removePtr);

// 从内存中读取32位整数值
const key = new Int32Array(memory.buffer, keyPtr, 1)[0];
const remove = new Int32Array(memory.buffer, removePtr, 1)[0];
console.log({key, remove}); // {key: 60, remove: 1}

free(keyPtr);
free(removePtr);

注意事项

  • 不要尝试直接在JS侧解析Go原生map、slice的内存布局,TinyGo不同版本的runtime内部结构可能调整,手动解析兼容性极差,JSON序列化是官方推荐的通用交互方式。
  • 所有通过malloc分配的WASM内存,使用完必须调用free释放,否则会造成WASM侧内存泄漏。
  • JS向Go传递字符串、数组等复杂参数时逻辑一致:将内容编码为UTF-8字节写入WASM内存,传入指针和长度即可在Go侧读取。

内容的提问来源于stack exchange,提问作者Leone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 01:30:57