WebAssembly

发布于 2022-11-13  805 次阅读


WebAssembly 于 2015 年首次发布,它的第一个示例是在 Firefox、 Google Chrome 和 Microsoft Edge 浏览器中运行的 Unity 的 Angry Bots 游戏。仅仅在发布四年后,它就成为正式的 web 标准,也成为继 HTML,CSS 和 JavaScript 之后的第四种 web 语言。到目前为止,在已安装的浏览器中, 94% 都支持 WebAssembly。它可以在 web 浏览器中实现接近原生的执行速度,使得移植桌面应用(如 AutoCAD)甚至电子游戏(如《毁灭战士3》)到网页中成为了可能。

几乎每个人都在追捧 WebAssembly。接下来我们就讨论一下它吧。

img

JavaScript 存在什么问题?

什么是 WebAssembly?

它是类似 C, C++ 那样的编程语言吗?

WebAssembly 如何工作?

WASM 是 web 应用程序发展的未来吗?

我们会回答以上所有的问题并带你了解 Web Assembly。它有可能将我们今天所了解到的网站变得更加强大。

系紧你的安全带,我们出发啦!⚡

JavaScript 存在什么问题?

img

JavaScript 不是为了高性能而开发的。

1995 年,Brenden Eich 为 Netscape 浏览器设计了 JavaScript 语言。它为当时的静态 web 网页提供了新的交互方式。

JavaScript 是一种解释型和动态类型的语言。如果一种语言的变量类型是在运行时检查的,那么就称它为动态类型语言。那它存在什么问题呢?如果我们用像 C++ 这样的静态类型语言来声明一个变量,像下面这样。

int x = 5;

从以上代码中可以看出,仅仅需要一条指令,编译器就能知道 x 的类型和内存地址。但是在 JavaScript 中,同样一句表达式,JS 引擎需要在每次程序运行时检查它是整型还是浮点类型,或者是其他有效的数据类型。所以 JavaScript 中的每条指令都需要经过多次类型检查和转换,这降低了它的运行速度。

下图展示了运行代码时, JavaScript 在各个阶段所花费的时间。

img

下图展示的是 WebAssembly 在各个阶段所花费的时间。

img

和 JavaScript 相比,WebAssembly 简化了整个编译过程,使其速度更快。

JavaScript 不是为 CPU 密集型和高性能的应用程序而开发的。

什么是 WebAssembly?

浏览器只能运行 JavaScript,但是如果我们拥有一个虚拟的微处理器,可以将任何高级语言转换成机器语言运行在所有的主流浏览器上,那将会怎么样呢?这就是 web 汇编所做的事情。

下面的例子中介绍了使用 C++ 编写的 adder 函数如何被转换为 WASM。

以下是将 C++ 代码转换成浏览器可识别的二进制的虚拟处理器示意图

img

它是类似 C, C++ 那样的编程语言吗?

img

WASM 完全不是一种编程语言。

不,它并不是一种编程语言🙂。简而言之,它是一种将某种编程语言转换成浏览器可识别的机器码的技术。

“ WASM(WebAssembly 的缩写)被设计成为其他语言的编译目标,我们可以将服务端代码(如 C 或 C++)编译成 WASM,并在浏览器中执行。”

img

让我们来看看吧!

WebAssembly 如何工作?

要了解什么是 web 汇编,我们需要知道什么是汇编。

什么是汇编语言和汇编器呢?

  • 每个处理器都有类似 x86 或者 ARM 的架构。此外,处理器只能识别机器码。
  • 编写机器码是乏味的,所以我们有针对架构/处理器设计的汇编语言。
  • 在汇编语言中,汇编器将指令转换成处理器可识别的机器码。

下图展示了用 C 语言编写的应用程序如何在电脑上运行。

img

与普通的汇编类似,WebAssembly 将 C++ 等高级语言编写的代码转换成浏览器可识别的机器码。

WebAssembly 入门

WebAssembly 是一个扩展名为 WASM 的文件。我们可以将它视为一个模块,并导入到 JavaScript 程序中。

项目目录中文件的交互 —

img

记住,WASM 不能直接与 DOM 交互。我们需要同时使用 JavaScript 和 WASM。

从上面的讨论中,我们了解到可以在浏览器中以接近原生的速度运行 C, C++ 等语言。为了实现它,我们需要执行以下几个步骤。🖖

1. 用你喜欢的语言编写应用程序

让我们编写一个简单的 C++ 函数来查找第 n 个斐波那契数。

// Following is a function that finds nth fibonacci written in C++
int fib(int n) {
    if (n <= 1)
        return n;
    return fib(n-1) + fib(n-2);
}

2. 创建一个 WASM 模块

现在,我们需要将写好的 C++ 文件转换为浏览器可识别的预编译 WASM 模块。

有很多种方法都可以将高级语言的代码转换成 WASM。在本教程中,我们将使用 Web Assembly Explorer.

第一步: 复制粘贴 C++ 代码,并点击 COMPILE 按钮

第二步: 点击 ASSEMBLE 按钮

第三步: 点击 DOWNLOAD 按钮,下载 wasm 文件

img
img

将下载的文件命名为 math.wasm 并复制到你的项目中去。

3. 分发模块 - 理想情况下,我们使用 CDN 来实现低延迟的文件分发。但是在这个示例中,我们将在本地运行 WASM 文件。

创建一个空的 script.js 文件。

你的项目目录应如下所示。

img

4. 加载 WASM 模块

我们将创建一个 loadWebAssembly() 函数,用来将指定文件转换为二进制数组。再将二进制数组转换为 WebAssembly 模块。必须通过 web assembly memory 来创建二进制数组。然后该模块的实例可以被浏览器读取。

你的 script.js 应该如下所示。

let math;
// Let's create a function called loadWebAssembly that converts given file into binary array buffer.
function loadWebAssembly(fileName) {
    return fetch(fileName)
        .then((response) => response.arrayBuffer())
        .then((buffer) => WebAssembly.compile(buffer)) // Buffer converted to Web Assembly
        .then((module) => {
            return new WebAssembly.Instance(module);
        }); // Instance of Web assmebly module is returened
}

//We call the function for math.wasm for the given Instance.
loadWebAssembly("math.wasm").then((instance) => {
    ...
});

5. 创建一个模块的实例。

现在到了最棘手的部分,我们需要在 JS 文件中引用 C++ 创建的函数。但是我们不能直接引用这些函数,而是需要使用 WASM 文件中生成的名称。这些名称可以在 Web Assembly Explorer 的 WAT 栏中找到。

使用下图中下划线标记的函数名。

img

被引用的变量都使用了下划线标记。

在你的 WAT 文件中,这些名字可能会不一样。

script.js中,第一部分是描述如何加载 WASM 文件的。

*第二部分创建了一些简单的 javascript 函数,用来比较 Javascript 和 WebAssembly 的性能。*🤓

//---------------------------PART 1--------------------------------------------------------
// Let's create a function called loadWebAssembly that converts given file into binary array buffer.
function loadWebAssembly(fileName) {
    return fetch(fileName)
        .then((response) => response.arrayBuffer())
        .then((buffer) => WebAssembly.compile(buffer))
        .then((module) => {
            return new WebAssembly.Instance(module);
        });
}

//We call the function for math.wasm
loadWebAssembly("math.wasm").then((instance) => {
    fibc = instance.exports._Z3fibi;

    console.log("Call your functions !");
});

//---------------------------PART 2 -----------------------------------------------
// Function written in Javascript for nth fibonacci
function fibj(n) {
    if (n <= 1) return n;
    return fibj(n - 1) + fibj(n - 2);
}

//This function gives the time required for C++ function
function perfoc(n) {
    var startTime = performance.now();
    var c = fibc(n);
    var endTime = performance.now();

    console.log(
        `Calculating nth Fibonacci with WASM took ${
            endTime - startTime
        } milliseconds,nth fibonacci is ${c}`
    );
}

// This function gives the time required for Javascript function
function perfoj(n) {
    var startTime = performance.now();
    var j = fibj(n);
    var endTime = performance.now();

    console.log(
        `Calculating nth Fibonacci with JS took ${
            endTime - startTime
        } milliseconds, nth fibonacci is ${j}`
    );
}

6. 调用实例的函数

现在在你的电脑上加载这个网站吧!

注意:你不能在本地直接运行 index.html,因为它不会加载 WASM 模块,除非使用 Live Server extension on Visual Studio Code 或 Xampp 在本地启动一个服务。

现在打开控制台,我们可以调用以下两个方法。

  1. fibj() → 使用简单的 Javascript 编写。
  2. fibc() → 使用 C++ 编写 并转换为 WebAssembly。
img

下面是使用纯 JavaScript 编写的方法 (fibj()) 和从 WebAssembly 导入的方法 (fibc()) 之间的比较。

img img WebAssembly 非常快!

fibj()fibc() 的执行时间是用下面的方法计算得出的:

  1. perfoj() → 计算得出 fibj() 的执行时间
  2. perfoc() → 计算得出 fibc() 的执行时间

由上面的 GIF 动图可以看出,fibj() (由 JavaScript 编写)的执行之间比 fibc()(由 WebAssembly 编写)要长。

WebAssembly 是 web 应用程序发展的未来吗?

使用 web 汇编,我们可以开发以接近原生速度运行的高性能 web 应用程序。我们可以执行视频处理、3D渲染、多媒体游戏、加密计算和 AR/VR 实时应用程序等任务。

所以基本上,任何需要大量编码和性能调优的应用程序都是 WebAssembly 的完美用例。

你可以自己尝试一下使用 WebAssembly!🧑‍🔧

作者:浅雪2333
链接:https://juejin.cn/post/7033585275791998990
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


欢迎欢迎~热烈欢迎~