WebAssembly是当今一个非常酷的话题。
WebAssembly是一种用于网络的新的低层次二进制格式。它不是你要写的编程语言,而是其他高级语言(目前是C、Rust和C++)将被编译成WebAssembly,从而有机会在浏览器中运行。
它被设计为快速、内存安全和开放。
你永远不会用WebAssembly(也叫WASM)写代码,相反,WebAssembly是其他语言被编译成的低水平格式。
这是继90年代的JavaScript之后,第二种可以被网络浏览器理解的语言。
WebAssembly是由W3C WebAssembly工作组制定的标准。今天,所有现代浏览器(Chrome、Firefox、Safari、Edge、移动浏览器)和Node.js都支持它。
我说过Node.js吗?是的,因为WebAssembly是在浏览器中诞生的,但Node从第8版开始就已经支持它了,你可以用JavaScript以外的任何语言构建Node.js应用程序的一部分。
不喜欢JavaScript的人,或者喜欢用其他语言编写的人,由于WebAssembly的出现,现在可以选择用不同于JavaScript的语言来编写网络上的部分应用程序。
不过要注意的是。WebAssembly并不是要取代JavaScript,而是要把用其他语言编写的程序移植到浏览器上,为用这些语言编写的应用程序的一部分提供动力,或者是预先存在的。
JavaScript和WebAssembly的代码相互配合,在网络上提供良好的用户体验。
这是一个双赢的网络,因为我们可以使用JavaScript的灵活性和易用性,并以WebAssembly的力量和性能作为补充。
安全性
WebAssembly代码在沙盒环境中运行,具有与JavaScript相同的安全策略,浏览器将确保同源和权限策略。
如果你对这个问题感兴趣,我建议你阅读WebAssembly中的内存和webassembly.org的安全文档。
性能
WebAssembly是为速度而设计的。它的主要目标是要非常、非常快。它是一种编译语言,这意味着程序在执行前会被转化为二进制文件。
它的性能可以达到与C语言等原生编译语言相近。
与JavaScript相比,它是一种动态和解释的编程语言,速度是无法比较的。WebAssembly总是要比JavaScript的性能好,因为在执行JavaScript时,浏览器必须解释指令,并在运行中进行任何优化。
今天谁在使用WebAssembly?
WebAssembly可以使用了吗?是的!许多公司已经在使用它,使他们的产品在网络上更好。
你可能已经用过的一个很好的例子是Figma,一个设计应用程序,我也用它来创建一些我在日常工作中使用的图形。这个应用程序在浏览器内运行,而且速度非常快。
这个应用程序是用React构建的,但应用程序的主要部分,即图形编辑器,是一个编译成WebAssembly的C++应用程序,使用WebGL在Canvas中渲染。
2018年初,AutoCAD发布了其流行的设计产品,在一个Web App内运行,使用WebAssembly来渲染其复杂的编辑器,该编辑器使用C++构建(并从桌面客户端代码库中迁移过来)
对于那些需要一块性能非常好的核心的产品来说,Web已经不是一个限制性的技术了。
如何使用WebAssembly?
C和C++应用程序可以使用Emscripten移植到WebAssembly,这个工具链可以把你的代码编译成两个文件。
- 一个
.wasm文件 - 一个
.js文件
其中.wasm 文件包含实际的WASM代码,而.js 文件包含胶水,允许JavaScript代码运行WASM。
Emscripten将为你做很多工作,比如将OpenGL调用转换为WebGL,为DOM API和其他浏览器和设备API提供绑定,提供文件系统工具,你可以在浏览器中使用,以及更多。默认情况下,这些东西在WebAssembly中是无法直接访问的,所以它是一个很大的帮助。
Rust代码则不同,它可以直接编译成WebAssembly作为其输出目标,而且有一个developer.mozilla.org/en-US/docs/…
WebAssembly在未来会有什么发展?它是如何发展的?
WebAssembly现在是1.0版本。它目前只正式支持3种语言(C、Rust、C++),但更多的语言即将到来。Go、Java和C#目前不能(正式)编译成WebAssembly,因为还没有对垃圾收集的支持。
当使用WebAssembly对浏览器API进行任何调用时,你目前需要先与JavaScript交互。目前正在进行的工作是使WebAssembly在浏览器中成为更一流的公民,使它能够直接调用DOM、Web Workers或其他浏览器API。
此外,还有一项工作正在进行中,即通过ES Modules规范,使JavaScript代码能够加载WebAssembly模块。
安装Emscripten
通过克隆emsdk GitHub repo来安装Emscripten。
git clone https://github.com/juj/emsdk.git
然后
现在,确保你安装了最新版本的Python。我的版本是2.7.10,这导致了一个TLS错误。
我不得不从www.python.org/getit/下载新的版本(2.7.15)进行安装,然后运行安装时附带的Install Certificates.command 程序。
然后
让它下载并安装软件包,然后运行
并通过运行将路径添加到你的shell中。
把C程序编译成WebAssembly
我将创建一个简单的C程序,并希望它能在浏览器中执行。
这是一个相当标准的 "Hello World "程序。
#include <stdio.h>
int main(int argc, char ** argv) {
printf("Hello World\n");
}
你可以用以下方法编译它
并运行./test ,将 "Hello World "打印到控制台。
让我们用Emscripten编译这个程序,在浏览器中运行它。
emcc test.c -s WASM=1 -o test.html
Emscripten给了我们一个html页面,它已经把WebAssembly程序编译好,准备运行。不过你需要从网络服务器上打开它,而不是从本地文件系统上打开,所以要启动一个本地网络服务器,例如http-server global npm包(如果你还没有安装,就用npm install -g http-server 安装它)。在这里,它是。

正如你所看到的,该程序运行并在控制台中打印出 "Hello World"。
这是运行编译为WebAssembly的程序的一种方法。另一种方法是使程序暴露出你要从JavaScript调用的函数。
从JavaScript中调用一个WebAssembly函数
让我们调整一下之前定义的Hello World。
包括emscripten headers。
#include <emscripten/emscripten.h>
并定义一个hello 函数。
int EMSCRIPTEN_KEEPALIVE hello(int argc, char ** argv) {
printf("Hello!\n");
return 8;
}
EMSCRIPTEN_KEEPALIVE 是需要的,以保持该函数如果不从 或其他在启动时执行的代码中调用,就会被自动剥离(因为编译器会优化所产生的编译代码并删除未使用的函数--但我们要从JS中动态调用,编译器现在知道这一点)。main()
这个小函数打印出Hello!并返回数字8。
现在,如果我们再次使用emcc 进行编译。
emcc test.c -s WASM=1 -o test.html -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap']"
这次我们添加了一个EXTRA_EXPORTED_RUNTIME_METHODS 标志,告诉编译器将ccall 和cwrap 函数留在模块对象上,我们将在JavaScript中使用。
现在我们可以再次启动Web服务器,一旦页面打开,就在控制台中调用Module.ccall('hello', 'number', null, null) ,它将打印 "Hello!"并返回8。

Module.ccall 接受的4个参数是C语言的函数名、返回类型、参数类型(一个数组)和参数(也是一个数组)。
例如,如果我们的函数接受2个字符串作为参数,我们会这样调用它。
Module.ccall('hello', 'number', ['string', 'string'], ['hello', 'world'])
我们可以使用的类型有:null,string,number,array,boolean 。
我们还可以通过使用Module.cwrap 函数为hello 函数创建一个 JavaScript 封装器,这样我们就可以通过使用 JS 对应函数来多次调用该函数。
const hello = Module.cwrap('hello', number, null, null)
