函数调用
syscall/jsjs.Global()js.ValuewindowGet()windowjs.ValueInvoke()js.ValueSet()js.NewCallback()func(args []js.Value)argspackage mainimport ( "sync"
"syscall/js")func main() {
jsGlobal := js.Global()
goFuncs := jsGlobal.Get("goFuncs")
goFuncs.Set("goFunc", js.NewCallback(func(args []js.Value) {
i, s := args[0].Int(), args[1].String()
i, s = i+2, s+"b"
res := jsGlobal.Get("jsFunc").Invoke(i, s)
i, s = res.Get("i").Int(), res.Get("s").String()
ret := args[2]
ret.Set("i", i)
ret.Set("s", s)
}))
wg := &sync.WaitGroup{}
wg.Add(1)
wg.Wait()
}<html>
<head>
<meta charset="utf-8">
<script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="wasm_exec.js"></script>
<script>
window.goFuncs = {} window.jsFunc = (i, s) => { return {i: i + 3, s: s + "c"}
} const go = new Go()
WebAssembly.instantiateStreaming(fetch("go_main.wasm"), go.importObject).
then(res => {
go.run(res.instance)
}) window.onload = () => { document.getElementById("btn").addEventListener("click", event => { let ret = {}
goFuncs.goFunc(1, "a", ret) console.dir(ret)
})
} </script>
</head>
<body>
<input id="btn" type="button" value="go" />
</body></html>go.run()main()main()内存访问
除了函数调用的交互,还可以通过内存直接共享数据。
instance.exports.meminstanceWebAssembly.instantiate*memTypedArray下面的例子会在 JS 端打开一个图片文件,显示在页面上,并将文件内容直接写入 Golang 使用的内存,在 Golang 中将图片的色调改变,再回调 JS 端来读取改变之后的图片,并显示在页面上。
package mainimport ( "bytes"
"image"
"reflect"
"sync"
"syscall/js"
"unsafe"
"github.com/anthonynsimon/bild/adjust"
"github.com/anthonynsimon/bild/imgio")type Ctx struct {
SetFileArrCb js.Value
SetImageToHueCb js.Value
}func setFile(ctx *Ctx, fileJsArr js.Value, length int) {
bs := make([]byte, length)
ptr := (*reflect.SliceHeader)(unsafe.Pointer(&bs)).Data
ctx.SetFileArrCb.Invoke(fileJsArr, ptr)
img, _, _ := image.Decode(bytes.NewReader(bs))
buf := &bytes.Buffer{}
imgio.JPEGEncoder(93)(buf, adjust.Hue(img, -150))
bs = buf.Bytes()
ptr = (*reflect.SliceHeader)(unsafe.Pointer(&bs)).Data
ctx.SetImageToHueCb.Invoke(ptr, len(bs))
}func main() {
jsGlobal := js.Global()
ctx := &Ctx{
SetFileArrCb: jsGlobal.Get("setFileArrCb"),
SetImageToHueCb: jsGlobal.Get("setImageToHueCb"),
}
goFuncs := jsGlobal.Get("goFuncs")
goFuncs.Set("setFile", js.NewCallback(func(args []js.Value) {
setFile(ctx, args[0], args[1].Int())
}))
wg := &sync.WaitGroup{}
wg.Add(1)
wg.Wait()
}<html>
<head>
<meta charset="utf-8">
<script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="wasm_exec.js"></script>
<script>
let goMemArr, fileType let setImageToElem = (elemId, dateArr) => { document.getElementById(elemId).src = URL.createObjectURL( new Blob([dateArr], {"type": fileType}))
} window.setFileArrCb = (fileArr, ptr) => {
goMemArr.set(fileArr, ptr)
} window.setImageToHueCb = (ptr, len) => {
setImageToElem("img-hue", goMemArr.slice(ptr, ptr + len))
} window.goFuncs = {} const go = new Go()
WebAssembly.instantiateStreaming(fetch("go_main.wasm"), go.importObject).
then(res => {
goMemArr = new Uint8Array(res.instance.exports.mem.buffer)
go.run(res.instance)
}
) let onFileSelected = event => { let reader = new FileReader() let file = event.target.files[0]
fileType = file.type
reader.onload = event => { let fileArr = new Uint8Array(event.target.result)
setImageToElem("img-ori", fileArr) window.goFuncs.setFile(fileArr, fileArr.length)
}
reader.readAsArrayBuffer(file)
} window.onload = () => { document.getElementById("file-input").addEventListener("change", onFileSelected)
} </script>
</head>
<body>
<input id="file-input" type="file" />
<br />
<image id="img-ori" />
<br />
<image id="img-hue" />
</body></html>放上一张浏览器截图,笔者选择了一张摄影名作《曼联球迷罗玉phone》,可以看到下方的图片色调被调整,球衣的颜色变为城城(队徽为笔者头像)的天蓝色。
