• 14行JavaScript教你使用WebAssembly


    作为一种比较新的web技术,WebAssembly可能会对web开发带来巨大的影响。随着2月MVP(Minimum Viable Product)版本的发布,WebAssembly的基本特性开始稳定,本文通过一个简单的示例来演示如何在页面上调用一个C++函数。

    基本组成

    要编写一个可以在浏览器中运行的WebAssembly应用,主要分为两个部分,可编译为WebAssembly的源语言和加载用的JavaScript。

    整个流程大致可以分为:

    1. 编写代码:用常用语言编写一个工程,可以是C、C++、Rust等。其他各种语言编译成WebAssembly可以参照这里
    2. 编译:将源码编译成WebAssembly的wasm文件。
    3. 引入:将之前生成的的wasm文件引入到前端工程中。
    4. 实例化:编写一段异步JavaScript代码加载和实例化wasm文件,使其他JavaScript文件可以无障碍使用。

    当然,这只是一个非常简化的流程,但是对于诸如本文的示例项目已经足够。首先,我们会使用C++编写一个简单的函数,然后使用在线工具将其编译成wasm文件(这样我们不用下载和安装任何编译工具),最后通过14行JavaScript代码加载并实例化。

    上述过程完成之后,我们就能够通过JavaScript代码来调用之前通过C++编写的函数了,是不是很神奇?

    编写代码

    首先我们会编写一个C++函数,当然了,前面提到过,这里不需要使用任何本地的编译链。取而代之的是一个WebAssembly Explorer的工具。它是一个类似CodePen的工具,可以左侧一列贴入C++代码,编译后下载对应的wasm文件。当然,类似的在线WebAssembly工具还有Mozilla提供的WebAssembly Studio

    首先打开WebAssembly Explorer页面,然后在左侧粘贴如下C++代码:

    int squarer(int num) {
      return num * num;
    }
    

    正如之前提到的,这是一个非常简单的示例,对于之前没有学习过C++的人也没有任何难度。

    编译

    下一步就是点击编译(“compile”)按钮,就能看见如下图所示界面,C++代码被编译撑了WAT格式(WebAssembly text format)的文本。

    14行JavaScript教你使用WebAssembly

    这里不详述WAT格式,展示该格式内容主要是因为相对于wasm的二进制格式,这种文本格式更易读。通过WAT文件中可以了解JavaScript和WebAssembly是如何交互的。例如本例中,在export关键字后面有_z7squareri这个导出的函数名,因为编译器对C++函数名的修饰(mangling)。

    这里需要特别注意,因为后面使用JavaScript对C++函数进行调用的时候需要依赖这个名字。当然,为了避免这种问题,可以将编译器选择为C99或者在函数外层增加extern "C"块:

    extern "C" {
      int squarer(int num) {
        return num * num;
      }
    }
    

    这样编译之后函数名称不会有变化。编译成的WAT文件内容如下图:

    14行JavaScript教你使用WebAssembly

    此时导出的函数名和原C++函数中的函数名保持一致。

    引入

    现在点击下载(“download”)按钮,并将下载的wasm文件重命名成squarer.wasm。

    创建一个文件夹,包含刚才下载的squarer.wasm文件,并新建下面两个文件:

    • index.html:包含标准网页的模板。
    • scripts.js:暂时这是一个空文件,下面就将编写实例化使用的JavaScript。

    实例化

    目前为止,HTML标准还不支持将wasm文件像JavaScript文件那样通过script标签直接引入。因此为了加载和实例化WebAssembly,需要通过JavaScript异步的调用WebAssembly API来完成这些操作。一共分为三步:

    1. 将wasm文件加载到数组缓冲区(array buffer)。
    2. 将加载的数组编译成WebAssembly模块
    3. 实例化WebAssembly模块。

    实例化之后,JavaScript就可以直接调用刚才WAT文件中export的函数和内存了。

    运行

    最后当然是期待人心的运行了。先来看看scripts.js内容:

    let squarer;
    
    function loadWebAssembly(fileName) {
      return fetch(fileName)
        .then(response => response.arrayBuffer())
        .then(bits => WebAssembly.compile(bits))
        .then(module => { return new WebAssembly.Instance(module) });
    };
      
    loadWebAssembly('squarer.wasm')
      .then(instance => {
        squarer = instance.exports._Z7squareri;
        console.log('Finished compiling! Ready when you are...');
      });
    

    这里的loadWebAssembly函数加载本地的wasm文件并进行实例化,最终返回一个WebAssembly模块实例。随后从模块中获取导出的函数,随后即可直接调用。这里需要特别注意,导出的函数名和刚才在WAT文件中看见的符号需要一致。由于C++编译器对函数名的修饰,建议在对所有需要导出给JavaScript的函数,都加上extern "C"块,避免函数名混乱导致的不匹配。

    在index.html文件中引入scripts.js之后,可以在控制台尝试调用squarer函数:

    14行JavaScript教你使用WebAssembly

    通过这个示例,我们了解了如何将C++代码编译成WebAssembly并在浏览器中执行。我们可以将更多的C、C++、Rust语言编写的工程放到浏览器中运行,以获得更高的执行效率。当然,还是要再次声明,这里只是一个简单的示例,如果函数的参数不是数字,还会有其他问题。随着WebAssembly工具链和集成工具的不断完善,相信编写基于WebAssembly的项目一定会更加方便。

    本文永久更新链接地址https://www.linuxidc.com/Linux/2018-05/152314.htm

  • 相关阅读:
    DripRoad(点滴之路)
    如何写优雅的代码
    .Net 一直在改变
    Protobufnet的完美解决方案
    关于msgpack序列化后的消息包是否再压缩
    失眠
    创建一个比微软性能更好空间更少的GUID
    msgpack与protobuf的简单性能测试对比
    分布式游戏服务器的登陆流程
    对象池的实现与性能测试
  • 原文地址:https://www.cnblogs.com/sweeeper/p/14361948.html
Copyright © 2020-2023  润新知