本文經(jīng)授權(quán)轉(zhuǎn)載自“碼洞”(ID:codehole) 從 Go 語言誕生以來,,它就開始不斷侵蝕 Java 、C,、C++ 語言的領(lǐng)地,。今年下半年 Go 語言發(fā)布了 1.11 版本,,引入了 WebAssembly 技術(shù),瀏覽器端 Javascript 的壟斷地位也開始遭遇 Go 語言的攻擊,。這次不同以往,,它意味著 Go 語言從后端滲透進了前端,進入了一個全新的世界,。 WebAssembly 運行原理WebAssembly 這個名字翻譯過來就是 「Web 匯編」,,也就是 Web 端的匯編語言。它是一段二進制字節(jié)碼程序,,Javascript 可以將這段二進制程序編譯成模塊,,然后再實例化這個模塊就可以調(diào)用字節(jié)碼邏輯了。WebAssembly 代碼運行的速度很快,,比 Javascript 要快很多,,Javascript 可以通過 WebAssembly 技術(shù)將關(guān)鍵性耗費性能的邏輯交給 WebAssembly 來做就可以明顯提升瀏覽器端的性能。 對比顯示,,使用 WebAssembly 運行斐波那契數(shù)列相比使用原生 Javascript 來實現(xiàn),,運行效率上能帶來 3.5 倍的提升。 WebAssembly 是一項比較新的技術(shù),,只有比較現(xiàn)代的瀏覽器才支持 WebAssembly,,例如 Chrome、FireFox瀏覽器,。 點擊查看更清晰 Go WebAssembly 運行原理Go 編譯器可以將代碼編譯成 WebAssembly 二進制字節(jié)碼,,被瀏覽器以靜態(tài)資源的形式加載進來后轉(zhuǎn)換成 Javascript 模塊。有了這個模塊,,瀏覽器可以直接操縱 Go 語言生成的二進制字節(jié)碼邏輯,。同時在 Go 語言編寫的代碼中可以直接讀寫瀏覽器里面 Javascript 運行時對象,,這樣就完成了 Javascript 和 Go 代碼的雙向交互,。 Go 語言直到 1.11 版本之后才開啟了對 WebAssembly 的支持。如需體驗,,必須升級,。 Go WebAssembly 初體驗下面我們就開始體驗一下 Chrome 瀏覽器與 Go 代碼是如何交互的。我們要實現(xiàn)一個功能,,在瀏覽器的輸入框里輸入一個正整數(shù),,然后調(diào)用 Go 代碼的斐波那契數(shù)列,再將結(jié)果再呈現(xiàn)在頁面上,。涉及到 4 個文件,,分別是 fib.go、main.go,、index.html,、wasm_exec.js,。 第一步使用 Go 代碼編寫 WebAssembly 模塊文件 fib.go,將 Go 語言實現(xiàn)的斐波那契函數(shù)注冊到 Javascript 全局環(huán)境,。這需要使用內(nèi)置的 syscall/js 模塊,,它提供了和 Javascript 引擎交互的接口。 // fib.go Go 語言注冊到 Javascript 引擎的函數(shù)在執(zhí)行時是異步的,,所以這個函數(shù)沒有返回值,在完成計算后需要通過調(diào)用「傳進來的回調(diào)函數(shù)」將結(jié)果傳遞到 Javascript 引擎,。注意 main 函數(shù)要保持運行狀態(tài)不要退出,,不然注冊進去的 fib 函數(shù)體就銷毀了。 第二步下面將 Go 代碼編譯成 WebAssembly 二進制字節(jié)碼,。 $ GOARCH=wasm GOOS=js go build -o fib.wasm fib.go 執(zhí)行完成后可以看到目錄下多了一個 fib.wasm,,這個就是字節(jié)碼文件。它的大小是 1.3M,,作為靜態(tài)文件傳遞到瀏覽器似乎有點大,,不過靜態(tài)文件服務器一般有 gzip 壓縮,壓縮后的大小只有幾百K,,這差不多也可以接受了,。 第三步編寫網(wǎng)頁文件 index.html,這個網(wǎng)頁包含兩個輸入框,,第一個輸入框用來輸入整數(shù)參數(shù),,第二個輸入框用來呈現(xiàn)計算結(jié)果。當?shù)谝粋€輸入框內(nèi)容發(fā)生改變時,,調(diào)用 Javascript 代碼,,執(zhí)行通過 WebAssembly 注冊的 fib 函數(shù)。需要傳入?yún)?shù) n 和回調(diào)的函數(shù),。 html> 注意代碼中引入了一個特殊的 JS 文件 wasm_exec.js,這個文件可以從 Go 安裝目錄的 misc 子目錄里找到,,將它直接拷貝過來,。它實現(xiàn)了和 WebAssembly 模塊交互的功能。 第四步運行靜態(tài)文件服務器,,這里不能使用普通的靜態(tài)文件服務器,,因為瀏覽器要求請求到的 WebAssemly 字節(jié)碼文件的 Content-Type 必須是 application/wasm,很多靜態(tài)文件服務器并不會因為擴展名是 wasm 就會自動使用這個 Content-Type,。但是 Go 內(nèi)置的 HTTP 服務器可以,。所以下面我們使用 Go 代碼簡單編寫一個靜態(tài)文件服務器。 package main 使用下面的命令運行它: $ go run main.go 第五步打開瀏覽器,,訪問 http://localhost:8000,,現(xiàn)在就可以體驗它的運行效果了,。 Javascript 真的需要擔心 Go WebAssembly 的威脅么?其實根本不用擔心,,WebAssembly 的目的是替換前端運行比較耗時的邏輯,,不是用來替換前端框架的,它也替換不了,。雖然開源社區(qū)冒出了一個 https://github.com/elliotforbes/oak 的 Go WebAssembly 框架,,可以讓你使用 Go 語言編寫前端應用程序。但是我仔細看了一下它的的源碼,,發(fā)現(xiàn)它原來只是一個玩具,,實現(xiàn)上沒幾行代碼,離真實的應用程序差距太遠,。 如果 Go WebAssembly 對 Javascript 是個威脅,,那么威脅 Javascript 的可不止 Go 語言了,,能夠?qū)⒋a編譯成 WebAssembly 字節(jié)碼的語言多達幾十種,。 希望將當前 Javascript 項目的部分代碼替換成 Go 語言,,成本也是顯而易見的。技術(shù)棧的切換成本,,字節(jié)碼的加載成本,,框架項目持續(xù)集成的成本都是需要考慮的點,。除非能獲得巨大的性能提升,否則使用純粹的 Javascript 來完成項目依然是最佳選擇,。 作者簡介:老錢,,著有《Redis 深度歷險》《深入理解 RPC》《快學 Go 語言》。 |
|