zoukankan      html  css  js  c++  java
  • 不安分的 Go 语言开始入侵 Web 前端领域了!( WebAssembly )

    参考:https://blog.csdn.net/csdnnews/article/details/84038848

    从 Go 语言诞生以来,它就开始不断侵蚀 Java 、C、C++ 语言的领地。今年下半年 Go 语言发布了 1.11 版本,引入了 WebAssembly 技术,浏览器端 Javascript 的垄断地位也开始遭遇 Go 语言的攻击。这次不同以往,它意味着 Go 语言从后端渗透进了前端,进入了一个全新的世界。

    WebAssembly 是一项比较新的技术,只有比较现代的浏览器才支持 WebAssembly,例如 Chrome、FireFox浏览器。

    Go 编译器可以将代码编译成 WebAssembly 二进制字节码,被浏览器以静态资源的形式加载进来后转换成 Javascript 模块。有了这个模块,浏览器可以直接操纵 Go 语言生成的二进制字节码逻辑。同时在 Go 语言编写的代码中可以直接读写浏览器里面 Javascript 运行时对象,这样就完成了 Javascript 和 Go 代码的双向交互。

    Go 语言直到 1.11 版本之后才开启了对 WebAssembly 的支持。如需体验,必须升级。

    第一步

    使用 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 引擎。注意 main 函数要保持运行状态不要退出,不然注册进去的 fib 函数体就销毁了。

    第二步

    下面将 Go 代码编译成 WebAssembly 二进制字节码。(我的是windows)

    set GOARCH=wasmset GOOS=js
    go build -o fib.wasm fib.go

    执行完成后可以看到目录下多了一个 fib.wasm,这个就是字节码文件。它的大小是 1.3M,作为静态文件传递到浏览器似乎有点大,不过静态文件服务器一般有 gzip 压缩,压缩后的大小只有几百K,这差不多也可以接受了。

    第三步

    编写网页文件 index.html,这个网页包含两个输入框,第一个输入框用来输入整数参数,第二个输入框用来呈现计算结果。当第一个输入框内容发生改变时,调用 Javascript 代码,执行通过 WebAssembly 注册的 fib 函数。需要传入参数 n 和回调的函数。

    <html>
    
    <head>
        <meta charset="utf-8">
        <meta http-equiv="expires" content="0"> 
        <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,这个文件可以从 Go 安装目录的 misc 子目录里找到,将它直接拷贝过来。它实现了和 WebAssembly 模块交互的功能。

    第四步

    运行静态文件服务器,这里不能使用普通的静态文件服务器,因为浏览器要求请求到的 WebAssemly 字节码文件的 Content-Type 必须是 application/wasm,很多静态文件服务器并不会因为扩展名是 wasm 就会自动使用这个 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))
    }

    现在在项目目录下有四个文件:main.go、index.html、fib.wasm、wasm_exec.js

    用以下命令编译运行:

    go run main.go

    第五步

    打开浏览器,访问 http://localhost:8000,现在就可以体验它的运行效果了。

    Javascript 真的需要担心 Go WebAssembly 的威胁么?

    其实根本不用担心,WebAssembly 的目的是替换前端运行比较耗时的逻辑,不是用来替换前端框架的,它也替换不了。虽然开源社区冒出了一个 https://github.com/elliotforbes/oak 的 Go WebAssembly 框架,可以让你使用 Go 语言编写前端应用程序。但是我仔细看了一下它的的源码,发现它原来只是一个玩具,实现上没几行代码,离真实的应用程序差距太远。

    如果 Go WebAssembly 对 Javascript 是个威胁,那么威胁 Javascript 的可不止 Go 语言了,能够将代码编译成 WebAssembly 字节码的语言多达几十种。

    希望将当前 Javascript 项目的部分代码替换成 Go 语言,成本也是显而易见的。技术栈的切换成本,字节码的加载成本,框架项目持续集成的成本都是需要考虑的点。除非能获得巨大的性能提升,否则使用纯粹的 Javascript 来完成项目依然是最佳选择。

    原作者简介:老钱,著有《Redis 深度历险》《深入理解 RPC》《快学 Go 语言》。

    熟练使用 Java、Python、Golang 等多种计算机语言,开发过游戏,制作过网站,写过消息推送系统和 MySQL 中间件,实现过开源的 ORM 框架、Web 框架、RPC 框架等,目前任职掌阅服务端技术专家。

  • 相关阅读:
    新内容记录:
    一个用于提取简体中文字符串中省,市和区并能够进行映射,检验和简单绘图的python模块
    django后台获取相同name名的数据
    python 使用qqwry.dat获取ip物理地址:速度快
    laydate设置起始时间,laydate设置开始时间和结束时间
    评论抓取:Python爬取微信在APPStore上的评论内容及星级
    H5上传压缩图片
    Django自带的加密算法及加密模块
    git入门
    WPF
  • 原文地址:https://www.cnblogs.com/pu369/p/10375724.html
Copyright © 2011-2022 走看看