--- title: WebAssembly概念 slug: WebAssembly/Concepts tags: - C - C++ - Emscripten - JavaScript - WebAssembly - 文本格式 - 概念 - 网络平台 translation_of: WebAssembly/Concepts ---

{{WebAssemblySidebar}}

本文解释了WebAssembly如何工作的概念,包括它的目标、它解决的问题以及它是如何在网络浏览器的渲染引擎中运行的。

WebAssembly是什么?

WebAssembly是一种运行在现代网络浏览器中的新型代码,并且提供新的性能特性和效果。它设计的目的不是为了手写代码而是为诸如C、C++和Rust等低级源语言提供一个高效的编译目标。

对于网络平台而言,这具有巨大的意义——这为客户端app提供了一种在网络平台以接近本地速度的方式运行多种语言编写的代码的方式;在这之前,客户端app是不可能做到的。

而且,你在不知道如何编写WebAssembly代码的情况下就可以使用它。WebAssembly的模块可以被导入的到一个网络app(或Node.js)中,并且暴露出供JavaScript使用的WebAssembly函数。JavaScript框架不但可以使用WebAssembly获得巨大性能优势和新特性,而且还能使得各种功能保持对网络开发者的易用性。

WebAssembly的目标

作为 W3C WebAssembly Community Group中的一项开放标准,WebAssembly是为下列目标而生的:

注:WebAssembly也用在网络和JavaScript环境之外(参考非网络嵌入)。

WebAssembly如何适应网络平台?

网络平台可以被想象成拥有两个部分:

从历史角度讲,虚拟机过去只能加载JavaScript。这对我们而言足够了,因为JavaScript足够强大从而能够解决人们在当今网络上遇到的绝大部分问题。尽管如此,当试图把JavaScript应用到诸如3D游戏、虚拟现实、增强现实、计算机视觉、图像/视频编辑以及大量的要求原生性能的其他领域的时候,我们遇到了性能问题(参考 WebAssembly 使用案例 获取更多细节)。

而且,下载、解析以及编译巨大的JavaScript应用程序的成本是过高的。移动平台和其他资源受限平台进一步放大了这些性能瓶颈。

WebAssembly是一门不同于JavaScript的语言,但是,它不是用来取代JavaScript的。相反,它被设计为和JavaScript一起协同工作,从而使得网络开发者能够利用两种语言的优势:

随着WebAssembly出现在了浏览器中,我们前面提到的虚拟机将会加载和运行两种类型的代码——JavaScript和WebAssembly。

不同类型的代码能够按照需要进行相互调用——WebAssembly的JavaScript API使用能够被正常调用的JavaScript函数封装了导出的WebAssembly代码,并且WebAssembly代码能够导入和同步调用常规的JavaScript函数。事实上,WebAssembly代码的基本单元被称作一个模块,并且WebAssembly的模块在很多方面都和ES2015的模块是等价的。

WebAssembly关键概念

为了理解WebAssembly如何在浏览器中运行,需要了解几个关键概念。所有这些概念都是一一映射到了WebAssembly的JavaScript API中。

JavaScript API为开发者提供了创建模块、内存、表格和实例的能力。给定一个WebAssembly实例,JavaScript代码能够调用普通JavaScript函数暴露出来的导出代码。通过把JavaScript函数导入到WebAssembly实例中,任意的JavaScript函数都能被WebAssembly代码同步调用。

因为JavaScript能够完全控制WebAssembly代码如何下载、编译运行,所以,JavaScript开发者甚至可以把WebAssembly想象成一个高效地生成高性能函数的JavaScript特性。

将来,WebAssembly模块将会像ES2015模块那样加载(使用<script type='module'>),这也就意味着JavaScript代码能够像轻松地使用一个ES2015模块那样来获取、编译和导入一个WebAssembly模块。

如何在我的app中使用WebAssembly?

上面我们讨论了WebAssembly向网络平台增加的基本要素:

现在让我们讨论如何在实践中使用这些基本要素。

WebAssembly生态系统处在初始阶段;更多的工具会毫无疑问得不断出现。当然,有两个主要的着手点:

让我们讨论这几项:

从C/C++移植

 

创建WASM代码的众多选项中有两个是在线WASM汇编程序或Emscripten。有许多在线WASM汇编程序可供选择,例如:

对于那些想知道从哪里开始的人来说,这些是很好的资源,但是他们缺少一些Emscripten的工具和优化。

Emscripten工具能够将一段C/C++代码,编译出:

简而言之,工作流程如下所示:

  1. Emscripten首先把C/C++提供给clang+LLVM——一个成熟的开源C/C++编译器工具链,比如,在OSX上是XCode的一部分。
  2. Emscripten将clang+LLVM编译的结果转换为一个.wasm二进制文件。
  3. 就自身而言,WebAssembly当前不能直接的存取DOM;它只能调用JavaScript,并且只能传入整形和浮点型的原始数据类型作为参数。这就是说,为了使用任何Web API,WebAssembly需要调用到JavaScript,然后由JavaScript调用Web API。因此,Emscripten创建了HTML和JavaScript胶水代码以便完成这些功能。

注意:计划将来允许WebAssembly直接调用Web API

JavaScript胶水代码并不是像你想象的那么简单。首先,Emscripten实现了流行的C/C++库,比如, SDLOpenGLOpenAL以及部分POSIX。这些库以Web API的形式实现,并且每个库需要一个JavaScript胶水代码来连接WebAssembly和低层的Web API。

因此,部分胶水代码实现了C/C++代码使用的库的功能。而且,胶水代码还包括调用前面提到的WebAssembly的JavaScript API来获取、加载和运行.wasm文件的逻辑。

生成的HTML文档加载JavaScript胶水文件,并且将stdout输出到{{htmlelement("textarea")}}。如果应用程序使用了OpenGL,HTML文档还会包含一个用来渲染目标的{{htmlelement("canvas")}}标签。

修改Emscripten的输出文件并将其转换为需要的web app是很容易的。

你可以在emscripten.org找到关于Emscripten的完整文档以及在Compiling from C/C++ to WebAssembly找到一个实现工具链并交叉编译你自己的C/C++应用程序为wasm的指南。

直接编写WebAssembly代码

你想构建自己的编译器,或者你自己的工具,或者创建一个能够在运行时生成WebAssembly代码的JavaScript库?

就像真实的汇编语言一样,WebAssembly的二进制格式也有文本表示——两者之间1:1对应。你可以手工书写或者生成这种格式然后使用这些工具(WebAssemby text-to-binary tools)中的任何一个把它转换为二进制格式。

这有一份如何做这些的简单指南,参考我们的文章转换WebAssembly文本格式为wasm

总结

本文给你解释了WebAssembly是什么,它为什么如此有用,它是如何适应网络的以及你如何才能使用它。

参考