Неугомонный язык Go начал вторгаться в область веб-интерфейса.

Go внешний интерфейс JavaScript WebAssembly

С момента рождения языка Go он продолжал разрушать территорию языков Java, C и C++. Во второй половине этого года язык Go выпустил версию 1.11, которая представила технологию WebAssembly, и монополия Javascript на стороне браузера стала подвергаться атаке со стороны языка Go. На этот раз все по-другому, это значит, что язык Go проник из бэкенда во фронтенд, в совершенно новый мир.

Как работает WebAssembly

Название WebAssembly переводится как «Веб-сборка», что является языком ассемблера на стороне Интернета. Это двоичная программа байт-кода.Javascript может скомпилировать эту двоичную программу в модуль, а затем создать экземпляр модуля для вызова логики байт-кода. Код WebAssembly работает очень быстро, намного быстрее, чем Javascript.Javascript может значительно повысить производительность на стороне браузера, передавая ключевую логику, требующую производительности, в WebAssembly через технологию WebAssembly.

Сравнение показывает, что использование WebAssembly для запуска последовательности Фибоначчи может повысить эффективность работы в 3,5 раза по сравнению с использованием собственного Javascript.

WebAssembly — относительно новая технология, и только современные браузеры поддерживают WebAssembly, например браузеры Chrome и FireFox.

Как работает Go WebAssembly

Компилятор Go может компилировать код в двоичный байт-код WebAssembly, который загружается браузером как статический ресурс и преобразуется в модуль Javascript. С помощью этого модуля браузер может напрямую манипулировать логикой двоичного байт-кода, сгенерированной языком Go. В то же время код, написанный на языке Go, может напрямую читать и записывать исполняемый объект Javascript в браузере, тем самым завершая двустороннее взаимодействие между Javascript и кодом Go.

Язык Go не поддерживал WebAssembly до версии 1.11. Для получения опыта необходимо обновиться.

Go WebAssembly первый опыт

Давайте начнем испытывать, как браузер Chrome взаимодействует с кодом Go. Мы хотим реализовать функцию, ввести положительное целое число в поле ввода браузера, затем вызвать последовательность Фибоначчи кода Go, а затем отобразить результат на странице. Задействованы четыре файла, а именно fib.go, main.go, index.html и wasm_exec.js.

первый шаг

Используйте код Go для написания файла модуля WebAssembly fib.go и регистрации функции Фибоначчи, реализованной на языке Go, в глобальной среде Javascript. Для этого необходимо использовать встроенный модуль syscall/js, который предоставляет интерфейс для взаимодействия с движком Javascript.

// fib.go
package main

import "syscall/js"

func main() {
	f_fib := func(params []js.Value) {
		var n = params[0].Int() // 输入参数
		var callback = params[1] // 回调参数
		var result = fib(n)
		// 调用回调函数,传入计算结果
		callback.Invoke(result)
	}
	// 注册全局函数
	js.Global().Set("fib", js.NewCallback(f_fib))
	// 保持 main 函数持续运行
        select {}
}

// 计算斐波那契数
func fib(n int) int {
        if n <= 0 {
          return 0
        }
	var result = make([]int, n+1)
	result[0] = 0
	result[1] = 1
	if n <= 1 {
		return result[n]
	}
	for i:=2;i<=n;i++ {
		result[i] = result[i-2] + result[i-1]
	}
	return result[n]
}

Функция, зарегистрированная языком Go в движке Javascript, выполняется асинхронно, поэтому эта функция не имеет возвращаемого значения.После завершения вычисления результат необходимо передать в движок Javascript, вызвав «пропущенную функцию обратного вызова». Обратите внимание, что основная функция должна оставаться запущенной и не завершаться, иначе зарегистрированное тело функции fib будет уничтожено.

второй шаг

Давайте скомпилируем код Go в двоичный байт-код WebAssembly.

$ GOARCH=wasm GOOS=js go build -o fib.wasm fib.go

После завершения выполнения вы можете увидеть, что в каталоге есть дополнительный файл fib.wasm, который является файлом байт-кода. Его размер составляет 1,3 МБ, что кажется немного большим для передачи в браузер в виде статического файла, но статический файловый сервер обычно имеет сжатие gzip, а сжатый размер составляет всего несколько сотен К, что почти приемлемо.

третий шаг

Напишите файл веб-страницы index.html, эта веб-страница содержит два поля ввода, первое поле ввода используется для ввода целочисленных параметров, а второе поле ввода используется для представления результата расчета. Когда содержимое первого поля ввода изменяется, вызывается код javascript для выполнения функции fib, зарегистрированной в WebAssembly. Функция, которая должна передать аргумент n и обратный вызов.

<html>

<head>
	<meta charset="utf-8">
	<title>Go wasm</title>
</head>

<style>
body {
	text-align: center
}
input {
	height: 50px;
	font-size: 20px;
}
#result {
	margin-left: 20px;
}
</style>

<body>
	<script src="wasm_exec.js"></script>
	<script>
	// 容纳 WebAssembly 模块的容器
 	var go = new Go();
	// 下载 WebAssembly 模块并执行模块
        // 也就是运行 Go 代码里面的 main 函数
        // 这样 fib 函数就注册进了 Javascript 全局环境
        WebAssembly.instantiateStreaming(fetch("fib.wasm"), go.importObject).then((result) => {
		go.run(result.instance);
	});

	function callFib() {
		let paramInput = document.getElementById("param")
		let n = parseInt(paramInput.value || "0")
		// 传入输入参数和回调函数
                // 回调函数负责呈现结果
                fib(n, function(result) {
        	    var resultDom = document.getElementById("result")
        	    resultDom.value = result
        	})
	}

	</script>
	// 输入发生变化时,调用 WebAssembly 的 fib 函数
        <input type="number" id="param" oninput="callFib()"/>
	<input type="text" id="result" />
</body>

</html>

Обратите внимание, что в код введен специальный js-файл wasm_exec.js, который можно найти в подкаталоге misc установочного каталога Go и скопировать напрямую. В нем реализована функция взаимодействия с модулями WebAssembly.

четвертый шаг

Для запуска статического файлового сервера здесь нельзя использовать обычный статический файловый сервер, поскольку браузер требует, чтобы Content-Type запрашиваемого файла байт-кода WebAssembly был application/wasm, а многие статические файловые серверы не смогут использовать wasm потому что расширение This Content-Type используется автоматически. Но встроенный в Go HTTP-сервер может. Итак, давайте просто напишем статический файловый сервер, используя код Go.

package main

import (
	"log"
	"net/http"
)

func main() {
	mux := http.NewServeMux()
	mux.Handle("/", http.FileServer(http.Dir(".")))
	log.Fatal(http.ListenAndServe(":8000", mux))
}

Запустите его с помощью следующей команды

$ go run main.go

пятый шаг

Откройте браузер и посетитеhttp://localhost:8000, и теперь вы можете испытать его в действии.

Действительно ли Javascript нужно беспокоиться об угрозе Go WebAssembly?

На самом деле беспокоиться не о чем, цель WebAssembly — заменить трудоемкую логику работы фронтенда, а не заменить фронтенд-фреймворк, и заменить его нельзя. Хотя сообщество открытого исходного кода придумалоGitHub.com/Elliot для…Платформа Go WebAssembly позволяет писать интерфейсные приложения с использованием языка Go. Но я присмотрелся к его исходникам и обнаружил, что это всего лишь игрушка ^_^, в реализации всего несколько строчек кода, а отставание от реального приложения слишком далеко.

Если Go WebAssembly представляет угрозу для javascript, то javascript угрожает не только язык Go.Существуют десятки языков, которые могут компилировать код в байт-код WebAssembly.

Хотите заменить часть кода текущего проекта javascript языком Go, стоимость также очевидна. Необходимо учитывать стоимость переключения стека технологий, стоимость загрузки байт-кода и стоимость непрерывной интеграции фреймворков. Если вы не получите огромного прироста производительности, использование чистого javascript для вашего проекта по-прежнему будет лучшим вариантом.

WeChat ищет «кодовую дыру», следите за публичной учетной записью «кодовая дыра»