如果熟悉Go Playground,那么就會(huì)知道在瀏覽器中安裝Go暫存器有多方便。想給別人看一段代碼片段嗎?是否想快速測(cè)試一些語(yǔ)法?基于瀏覽器的代碼墊很有幫助。關(guān)于這一點(diǎn),我創(chuàng)建了一個(gè)新的游樂(lè)場(chǎng)。關(guān)于這個(gè)新游樂(lè)場(chǎng)的妙處在于,它不使用遠(yuǎn)程服務(wù)器來(lái)運(yùn)行代碼,而只是用于對(duì)其進(jìn)行編譯。該代碼在您的瀏覽器中使用Web Assembly運(yùn)行。
它是如何工作的?
當(dāng)用戶單擊“運(yùn)行”時(shí),代碼將發(fā)送回我們的服務(wù)器。服務(wù)器是用Go語(yǔ)言編寫(xiě)的。因此,API的處理程序如下所示:
func compileCodeHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
// Get code from params
type parameters struct {
Code string
}
decoder := json.NewDecoder(r.Body)
params := parameters{}
err := decoder.Decode(?ms)
if err != nil {
respondWithError(w, 500, "Couldn't decode parameters")
return
}
// create file system location for compilation path
usr, err := user.Current()
if err != nil {
respondWithError(w, 500, "Couldn't get system user")
return
}
workingDir := filepath.Join(usr.HomeDir, ".wasm", uuid.New().String())
err = os.MkdirAll(workingDir, os.ModePerm)
if err != nil {
respondWithError(w, 500, "Couldn't create directory for compilation")
return
}
defer func() {
err = os.RemoveAll(workingDir)
if err != nil {
respondWithError(w, 500, "Couldn't clean up code from compilation")
return
}
}()
f, err := os.Create(filepath.Join(workingDir, "main.go"))
if err != nil {
respondWithError(w, 500, "Couldn't create code file for compilation")
return
}
defer f.Close()
dat := []byte(params.Code)
_, err = f.Write(dat)
if err != nil {
respondWithError(w, 500, "Couldn't write code to file for compilation")
return
}
// compile the wasm
const outputBinary = "main.wasm"
os.Setenv("GOOS", "js")
os.Setenv("GOARCH", "wasm")
cmd := exec.Command("go", "build", "-o", outputBinary)
cmd.Dir = workingDir
stderr, err := cmd.StderrPipe()
if err != nil {
respondWithError(w, 500, err.Error())
return
}
if err := cmd.Start(); err != nil {
respondWithError(w, 500, err.Error())
return
}
stdErr, err := ioutil.ReadAll(stderr)
if err != nil {
respondWithError(w, 500, err.Error())
return
}
stdErrString := string(stdErr)
if stdErrString != "" {
parts := strings.Split(stdErrString, workingDir)
if len(parts) < 2 {
respondWithError(w, 500, stdErrString)
return
}
respondWithError(w, 400, parts[1])
return
}
if err := cmd.Wait(); err != nil {
respondWithError(w, 500, err.Error())
return
}
// write wasm binary to response
dat, err = ioutil.ReadFile(filepath.Join(workingDir, outputBinary))
if err != nil {
respondWithError(w, 500, err.Error())
return
}
w.Write(dat)
}
如您所見(jiàn),處理程序僅將代碼作為輸入,并以WASM字節(jié)片作為響應(yīng)。
前端呢?
前端非常簡(jiǎn)單。首先,我們需要在頁(yè)面中包括Go WASM的官方執(zhí)行者。假設(shè)您的計(jì)算機(jī)上已安裝Go,可以在以下位置找到此JavaScript文件:
$(go env GOROOT)/misc/wasm/wasm_exec.js
然后在您的html正文中包含腳本:
<!DOCTYPE html>
<html>
<head>
<title>Qvault Classroom - Learn Coding</title>
</head>
<body>
<script src="wasm_exec.js"></script>
</body>
</html>
因?yàn)镼vault Classroom的前端是作為Vue.js單頁(yè)應(yīng)用程序編寫(xiě)的,所以我創(chuàng)建了一個(gè)小的es6模塊,該模塊運(yùn)行WASM字節(jié)數(shù)組并將輸出作為行數(shù)組返回:
const go = new window.Go();export default async function runGoWasm(rawData) {
const result = await WebAssembly.instantiate(rawData, go.importObject);
let oldLog = console.log;
let stdOut = [];
console.log = (line) => {stdOut.push(line);};
await go.run(result.instance);
console.log = oldLog;
return stdOut;
}
關(guān)于如何使用Web Assembly在瀏覽器中運(yùn)行Go 的內(nèi)容,介紹到這里就結(jié)束了。如果還想了解更多關(guān)于Web Assembly的信息,請(qǐng)繼續(xù)關(guān)注中培偉業(yè)。