
用 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 是一种极具潜力的技术,可以将多种不同的语言生态系统相互集成。
参考文献
- WebAssembly.org:https://webassembly.org
- WebAssembly 规范:https://github.com/WebAssembly/spec
- Go 句子库:https://github.com/neurosnap/sentences
- Syscall/js 软件包:https://pkg.go.dev/syscall/js
- 使用 Go 的 Golangbot Webassembly:https://golangbot.com/webassembly-using-go
照片由 Venti Views 在 Unsplash 上拍摄。