(原) Go与WebAssembly之四

原创文章,请后转载,并注明出处。

以下内容就是复制的,好多地方没理解。也就不便注释了。待我内力大增时再来消化。

此例子经常会运行不成功,显示错误信息: attempting to access detached ArrayBuffer(试图访问分离的ArrayBuffer )。错误位于go代码ctx.SetImageToHueCb.Invoke(ptr, len(bs))。多次运行发现:一般一百多K的图片,刷新浏览器即选择运行就没问题,第二次运行亦出错。超过一百K太多,随便运行都出错。

####内存访问

除了函数调用的交互,还可以通过内存直接共享数据。

Golang 端使用的内存空间,通过 instance.exports.mem 暴露给 JS 端,这里 instance 为 WebAssembly.instantiate* 函数实例化 wasm 模块得到的 instance。可以通过 mem 创建 TypedArray,以此在 JS 直接读写 Golang 使用的内存。

下面的例子会在 JS 端打开一个图片文件,显示在页面上,并将文件内容直接写入 Golang 使用的内存,在 Golang 中将图片的色调改变,再回调 JS 端来读取改变之后的图片,并显示在页面上。

package main

import (
    "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.FuncOf(func(this js.Value,args []js.Value) interface{} {
        setFile(ctx, args[0], args[1].Int())
        return nil
    }))
    wg := &sync.WaitGroup{}
    wg.Add(1)
    wg.Wait()
}
<html>
  <head>
    <meta charset="utf-8">
    <script src="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>

在html中,涉及到一些ES6(ECMAScript 6.0)等标准的语法不是太明白,看来也需要学习。

ES6 2015 -> ES7 2016 -> ES8 2018 -> ES9 2018 -> ES10 2019

看看这个生产线,好象错过了几个亿…..

fetch 发起异步请求

//ES5 $(’#bt’).click(function (e) { //doing something }) //ES6 $(’#bt’).click(e => { //doing something })

相关文章