cover image
< 主页
Web

用 WebAssembly 将 Go 库集成到 JavaScript 网页中

有了 WebAssembly,你可以将不同的编程语言整合在一起。这就为在另一个不同的平台上使用用一种语言编写的优秀库提供了新的可能性。在本文中,我将展示如何在 JavaScript 网页中集成用于句子标记化的 Go 库。通常情况下,你无法在网页浏览器中运行 Go 代码,但有了 WebAssembly 技术,你就可以了。

WebAssembly

WebAssembly 是 W3C 的一个规范,它定义了可执行程序的二进制和文本格式,既可以在浏览器中运行,也可以独立运行。 WebAssembly 程序在基于堆栈的虚拟机(VM)中运行。WebAssembly 的名称来源于非常接近实际硬件的汇编编程语言,它定义了一种比汇编语言更独立于设备的语言,但仍然是非常低级的语言。 截至撰写本文时,全球 97.11 % 的浏览器(caniuse.com)都支持 WebAssembly。W3C WebAssembly 规范有各种扩展,浏览器对它们的支持程度各不相同。

Sentences Go 库

Sentences 是一个用于句子标记化的 Go 库,由 Eric Bower 编写,在 GitHub 上以开源形式发布。由于无法在浏览器中本地运行 Go 代码,只能运行 JavaScript,因此有了使用 WebAssembly 将该库集成到网站中的想法。

将 Sentences 库暴露给 JavaScript

你可以编写一个 Go 封装应用程序,利用 syscall/js package of Go 来集成 Sentences 库。请注意,在撰写本文时,该软件包被标记为 "实验性"。 具体来说,我们将使用 js.FuncOf 函数。以下是 Go 应用程序的完整源代码:

package main

import (
	"fmt"
	"strings"
	"syscall/js"

	"github.com/neurosnap/sentences/english"
)

func sentenceWrapper() js.Func {
	sentenceFunc := js.FuncOf(func(this js.Value, args []js.Value) any {
		if len(args) != 1 {
			return "Invalid no of arguments passed"
		}
		inputSentence := args[0].String()
		fmt.Printf("input %s\n", inputSentence)
		tokenizer, err := english.NewSentenceTokenizer(nil)
		if err != nil {
			panic(err)
		}

		sentences := tokenizer.Tokenize(inputSentence)
		for _, s := range sentences {
			fmt.Println(s.Text)
		}

		var sentenceTexts []string
		for _, s := range sentences {
			trimmedText := strings.TrimSpace(s.Text)
			sentenceTexts = append(sentenceTexts, trimmedText)
		}

		allSentences := strings.Join(sentenceTexts, "\n") // Join all sentences separated by a space
		return allSentences

	})
	return sentenceFunc
}

func main() {
	fmt.Println("Go Web Assembly")
	js.Global().Set("tokenizeSentence", sentenceWrapper())
	<-make(chan struct{})
}

你可以看到,现在 sentenceWrapper 函数在 JavaScript 中暴露为 tokenizeSentence 函数。它的参数是要标记的字符串,并返回标记后的字符串。与句子库的实际集成发生在传递给 js.FuncOf 的函数中。

编译 Wrapper

使用以下 Go 编译命令将应用程序编译为 WebAssembly:

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

如果一切顺利,你应该在文件夹中找到 main.wasm 文件作为输出。这就是将加载到 JavaScript 应用程序中的 WebAssembly 二进制文件。

在网站中集成 WebAssembly Go

库 为了将 main.wasm 文件加载到网页中,你需要以下代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <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>
  </head>
  <body>
    <textarea id="sentenceinput" name="jsoninput" cols="80" rows="20"></textarea>
    <input
      id="button"
      type="submit"
      name="button"
      value="tokenize"
      onclick="tokenize(sentenceinput.value)"
    />
    <textarea id="jsonoutput" name="jsonoutput" cols="80" rows="20"></textarea>
  </body>
  <script>
    var tokenize = function (input) {
      jsonoutput.value = tokenizeSentence(input);
    };
  </script>
</html>

在浏览器中运行此网页时,还需要当前目录中的实用 JavaScript 文件 wasm_exec.js。您可以从以下地址获取该文件:

cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

正如您从 JavaScript 代码中看到的,当点击 "tokenize "按钮时,JavaScript 将调用外露的 tokenizeSentence() 函数。输入字段的内容被用作函数的参数,返回值被写入右侧的文本字段。 请注意,您需要运行网络服务器才能在浏览器中运行网页。您可以使用以下代码在 Go 中构建网络服务器:

server/server.go

package main

import (
	"fmt"
	"net/http"
)

func main() {
	err := http.ListenAndServe(":9090", http.FileServer(http.Dir("../")))
	if err != nil {
		fmt.Println("Failed to start server", err)
		return
	}
}

启动网络服务器后,你可以在浏览器中访问页面: http://localhost:9090

感谢来自 golangbot.com 的 Naveen Ramanathan 对本文的启发。

结语

一如既往,我希望本文能在某些方面帮助你保持好奇心。WebAssembly 是一种极具潜力的技术,可以将多种不同的语言生态系统相互集成。

参考文献

照片由 Venti ViewsUnsplash 上拍摄。

已出版

9 7月 2024

Thomas Derflinger

作者:托马斯-德弗林格

我是一名富有远见的企业家和软件开发人员。在这个博客中,我主要写网络编程和物联网等相关主题