午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

不安分的 Go 語(yǔ)言開(kāi)始入侵 Web 前端領(lǐng)域了!

 長(zhǎng)沙7喜 2018-11-30



本文經(jīng)授權(quán)轉(zhuǎn)載自“碼洞”(ID:codehole)

從 Go 語(yǔ)言誕生以來(lái),它就開(kāi)始不斷侵蝕 Java 、C、C++ 語(yǔ)言的領(lǐng)地。今年下半年 Go 語(yǔ)言發(fā)布了 1.11 版本,引入了 WebAssembly 技術(shù),瀏覽器端 Javascript 的壟斷地位也開(kāi)始遭遇 Go 語(yǔ)言的攻擊。這次不同以往,它意味著 Go 語(yǔ)言從后端滲透進(jìn)了前端,進(jìn)入了一個(gè)全新的世界。


WebAssembly 運(yùn)行原理


WebAssembly 這個(gè)名字翻譯過(guò)來(lái)就是 「Web 匯編」,也就是 Web 端的匯編語(yǔ)言。它是一段二進(jìn)制字節(jié)碼程序,Javascript 可以將這段二進(jìn)制程序編譯成模塊,然后再實(shí)例化這個(gè)模塊就可以調(diào)用字節(jié)碼邏輯了。WebAssembly 代碼運(yùn)行的速度很快,比 Javascript 要快很多,Javascript 可以通過(guò) WebAssembly 技術(shù)將關(guān)鍵性耗費(fèi)性能的邏輯交給 WebAssembly 來(lái)做就可以明顯提升瀏覽器端的性能。

對(duì)比顯示,使用 WebAssembly 運(yùn)行斐波那契數(shù)列相比使用原生 Javascript 來(lái)實(shí)現(xiàn),運(yùn)行效率上能帶來(lái) 3.5 倍的提升。

WebAssembly 是一項(xiàng)比較新的技術(shù),只有比較現(xiàn)代的瀏覽器才支持 WebAssembly,例如 Chrome、FireFox瀏覽器。

點(diǎn)擊查看更清晰


Go WebAssembly 運(yùn)行原理


Go 編譯器可以將代碼編譯成 WebAssembly 二進(jìn)制字節(jié)碼,被瀏覽器以靜態(tài)資源的形式加載進(jìn)來(lái)后轉(zhuǎn)換成 Javascript 模塊。有了這個(gè)模塊,瀏覽器可以直接操縱 Go 語(yǔ)言生成的二進(jìn)制字節(jié)碼邏輯。同時(shí)在 Go 語(yǔ)言編寫的代碼中可以直接讀寫瀏覽器里面 Javascript 運(yùn)行時(shí)對(duì)象,這樣就完成了 Javascript 和 Go 代碼的雙向交互。

Go 語(yǔ)言直到 1.11 版本之后才開(kāi)啟了對(duì) WebAssembly 的支持。如需體驗(yàn),必須升級(jí)。


Go WebAssembly 初體驗(yàn)


下面我們就開(kāi)始體驗(yàn)一下 Chrome 瀏覽器與 Go 代碼是如何交互的。我們要實(shí)現(xiàn)一個(gè)功能,在瀏覽器的輸入框里輸入一個(gè)正整數(shù),然后調(diào)用 Go 代碼的斐波那契數(shù)列,再將結(jié)果再呈現(xiàn)在頁(yè)面上。涉及到 4 個(gè)文件,分別是 fib.go、main.go、index.html、wasm_exec.js。

第一步

使用 Go 代碼編寫 WebAssembly 模塊文件 fib.go,將 Go 語(yǔ)言實(shí)現(xiàn)的斐波那契函數(shù)注冊(cè)到 Javascript 全局環(huán)境。這需要使用內(nèi)置的 syscall/js 模塊,它提供了和 Javascript 引擎交互的接口。

// fib.go
package main

import 'syscall/js'

func main() {
    f_fib := func(params []js.Value) {
        var n = params[0].Int() // 輸入?yún)?shù)
        var callback = params[1// 回調(diào)參數(shù)
        var result = fib(n)
        // 調(diào)用回調(diào)函數(shù),傳入計(jì)算結(jié)果
        callback.Invoke(result)
    }
    // 注冊(cè)全局函數(shù)
    js.Global().Set('fib', js.NewCallback(f_fib))
    // 保持 main 函數(shù)持續(xù)運(yùn)行
 select {}
}

// 計(jì)算斐波那契數(shù)
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<>
        result[i] = result[i-2] + result[i-1]
    }
    return result[n]
}

Go 語(yǔ)言注冊(cè)到 Javascript 引擎的函數(shù)在執(zhí)行時(shí)是異步的,所以這個(gè)函數(shù)沒(méi)有返回值,在完成計(jì)算后需要通過(guò)調(diào)用「?jìng)鬟M(jìn)來(lái)的回調(diào)函數(shù)」將結(jié)果傳遞到 Javascript 引擎。注意 main 函數(shù)要保持運(yùn)行狀態(tài)不要退出,不然注冊(cè)進(jìn)去的 fib 函數(shù)體就銷毀了。

第二步

下面將 Go 代碼編譯成 WebAssembly 二進(jìn)制字節(jié)碼。

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

執(zhí)行完成后可以看到目錄下多了一個(gè) fib.wasm,這個(gè)就是字節(jié)碼文件。它的大小是 1.3M,作為靜態(tài)文件傳遞到瀏覽器似乎有點(diǎn)大,不過(guò)靜態(tài)文件服務(wù)器一般有 gzip 壓縮,壓縮后的大小只有幾百K,這差不多也可以接受了。

第三步

編寫網(wǎng)頁(yè)文件 index.html,這個(gè)網(wǎng)頁(yè)包含兩個(gè)輸入框,第一個(gè)輸入框用來(lái)輸入整數(shù)參數(shù),第二個(gè)輸入框用來(lái)呈現(xiàn)計(jì)算結(jié)果。當(dāng)?shù)谝粋€(gè)輸入框內(nèi)容發(fā)生改變時(shí),調(diào)用 Javascript 代碼,執(zhí)行通過(guò) WebAssembly 注冊(cè)的 fib 函數(shù)。需要傳入?yún)?shù) n 和回調(diào)的函數(shù)。

html>

head>
    meta charset='utf-8'>
    title>Go wasmtitle>
head>

style>
body {
    text-align: center
}
input {
    height50px;
    font-size20px;
}
#result {
    margin-left20px;
}
style>


body>
    script src='wasm_exec.js'>script>
    script>
        // 容納 WebAssembly 模塊的容器
        var go = new Go();
        // 下載 WebAssembly 模塊并執(zhí)行模塊
        // 也就是運(yùn)行 Go 代碼里面的 main 函數(shù)
        // 這樣 fib 函數(shù)就注冊(cè)進(jìn)了 Javascript 全局環(huán)境
        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')
            // 傳入輸入?yún)?shù)和回調(diào)函數(shù)
            // 回調(diào)函數(shù)負(fù)責(zé)呈現(xiàn)結(jié)果
            fib(n, function(result{
                var resultDom = document.getElementById('result')
                resultDom.value = result
            })
        }

    script>

    // 輸入發(fā)生變化時(shí),調(diào)用 WebAssembly 的 fib 函數(shù)
    input type='number' id='param' oninput='callFib()'/>
    input type='text' id='result' />
body>

html>

注意代碼中引入了一個(gè)特殊的 JS 文件 wasm_exec.js,這個(gè)文件可以從 Go 安裝目錄的 misc 子目錄里找到,將它直接拷貝過(guò)來(lái)。它實(shí)現(xiàn)了和 WebAssembly 模塊交互的功能。

第四步

運(yùn)行靜態(tài)文件服務(wù)器,這里不能使用普通的靜態(tài)文件服務(wù)器,因?yàn)闉g覽器要求請(qǐng)求到的 WebAssemly 字節(jié)碼文件的 Content-Type 必須是 application/wasm,很多靜態(tài)文件服務(wù)器并不會(huì)因?yàn)閿U(kuò)展名是 wasm 就會(huì)自動(dòng)使用這個(gè) Content-Type。但是 Go 內(nèi)置的 HTTP 服務(wù)器可以。所以下面我們使用 Go 代碼簡(jiǎn)單編寫一個(gè)靜態(tài)文件服務(wù)器。

package main

import (
    'log'
    'net/http'
)

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

使用下面的命令運(yùn)行它:

go run main.go

第五步

打開(kāi)瀏覽器,訪問(wèn) http://localhost:8000,現(xiàn)在就可以體驗(yàn)它的運(yùn)行效果了。


Javascript 真的需要擔(dān)心 Go WebAssembly 的威脅么?


其實(shí)根本不用擔(dān)心,WebAssembly 的目的是替換前端運(yùn)行比較耗時(shí)的邏輯,不是用來(lái)替換前端框架的,它也替換不了。雖然開(kāi)源社區(qū)冒出了一個(gè) https://github.com/elliotforbes/oak 的 Go WebAssembly 框架,可以讓你使用 Go 語(yǔ)言編寫前端應(yīng)用程序。但是我仔細(xì)看了一下它的的源碼,發(fā)現(xiàn)它原來(lái)只是一個(gè)玩具,實(shí)現(xiàn)上沒(méi)幾行代碼,離真實(shí)的應(yīng)用程序差距太遠(yuǎn)。

如果 Go WebAssembly 對(duì) Javascript 是個(gè)威脅,那么威脅 Javascript 的可不止 Go 語(yǔ)言了,能夠?qū)⒋a編譯成 WebAssembly 字節(jié)碼的語(yǔ)言多達(dá)幾十種。

希望將當(dāng)前 Javascript 項(xiàng)目的部分代碼替換成 Go 語(yǔ)言,成本也是顯而易見(jiàn)的。技術(shù)棧的切換成本,字節(jié)碼的加載成本,框架項(xiàng)目持續(xù)集成的成本都是需要考慮的點(diǎn)。除非能獲得巨大的性能提升,否則使用純粹的 Javascript 來(lái)完成項(xiàng)目依然是最佳選擇。

作者簡(jiǎn)介:老錢,著有《Redis 深度歷險(xiǎn)》《深入理解 RPC》《快學(xué) Go 語(yǔ)言》。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多