WebAssembly 学习笔记(一)

WebAssembly 学习笔记(一)

以下内容都是我在学习WebAssembly的过程中根据官方的开发手册的一些笔记。
这部分的内容是介绍WebAssembly的相关概念、该工具的目的、该工具想要解决的问题以及它如何可以在浏览器中的渲染引擎中使用。
原文链接在这里。

WebAssembly 概念

WebAssembly是一种新的代码类型,可以在现代的web浏览器中运行并提供新特性以及性能增益。它本身并不是设计为一种手写代码,而是作为其他源代码如C,C++,Rust的一种高效的编译对象(compilation target)。
这个工具对于web平台具有巨大的影响力,它它提供了一种方式让各种源代码可以在web上以接近原生速度(near-native speed),这种运行在web端的程序以前达不到这个效果。

此外,你甚至不需要知道如何去创建WebAssembly去使用它。WebAssembly模块(WebAssembly modules)可以被导入到web (或者Node.js)App中,通过JavaScript暴露WebAssembly的功能来使用。
JavaScript 框架可以使用WebAssembly去获得巨大的性能优点以及新的特性,同时仍然可以保证web 开发者可以轻松使用功能。

WebAssembly 目的

WebAssembly正在作为一个公开的标准,主要在W3C WebAssembly社区获得广泛认可,主要的目的如下:

  • 快速、高效、便捷。WebAssembly 代码可以通过利用普遍的硬件性能以近似原生的速度跨平台运行。

  • 可读性和可调试性–WebAssembly是一种低级别的汇编语言,但它确实有一种人类可读的文本格式(其规范仍在定稿中),允许用手编写、查看和调试代码。

  • 保持安全 - WebAssembly被指定为在安全的沙盒执行环境中运行。像其他网络代码一样,它将执行浏览器的同源和权限策略。

  • 不打断web–WebAssembly的设计使它能与其他网络技术很好地配合,并保持向后(backwards)兼容。

WebAssembly如何适应web平台?

web可以被认为是有两个部分。

  • 一个运行网络应用程序代码的虚拟机(VM),例如为你的应用程序提供动力的JavaScript代码。
  • 一组web API,网络应用可以调用它来控制网络浏览器/设备的功能,并使事情发生(DOM、CSSOM、WebGL、IndexedDB、网络音频API等)。

ps:
DOM:
文档对象模型 (DOM) 将 web 页面与到脚本或编程语言连接起来。通常是指 JavaScript,但将 HTML、SVG 或 XML 文档建模为对象并不是 JavaScript 语言的一部分。

CSSOM:CSS 对象模型 (CSSOM) 是树形形式的所有 CSS 选择器和每个选择器的相关属性的映射,具有树的根节点,同级,后代,子级和其他关系。

WebGL:WebGL(Web 图形库)是一个 JavaScript API,可在任何兼容的 Web 浏览器中渲染高性能的交互式 3D 和 2D 图形,而无需使用插件。

IndexedDB:IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索。

历史上,虚拟机一直只能加载JavaScript。这对我们来说效果很好,因为JavaScript足够强大,可以解决今天人们在web上遇到的大多数问题。然而,当我们试图将JavaScript用于更密集的用例时,如3D游戏、虚拟和增强现实(Virtual and Augmented Reality)、计算机视觉、图像/视频编辑,以及其他一些需要原生性能的领域时,我们遇到了性能问题(更多想法见WebAssembly用例)。

此外,下载、解析和编译非常大的JavaScript应用程序的成本可能是令人望而却步的。移动和其他资源受限的平台会进一步放大这些性能瓶颈。

WebAssembly是一种不同于JavaScript的语言,但它并不打算作为一种替代。相反,它被设计为补充并与JavaScript一起工作,使Web开发者能够利用这两种语言的优点:

  • JavaScript是一种高级语言,具有足够的灵活性和表现力来编写网络应用程序。它有很多优点–它是动态类型的,不需要编译步骤,并且有一个巨大的生态系统,提供强大的框架、库和其他工具。
  • WebAssembly是一种类似于汇编的低级语言,具有紧凑的二进制格式,运行时具有接近原生的性能,为C++和Rust等具有底层内存模型的语言提供了一个编译目标,以便它们能够在网络上运行。(请注意,WebAssembly的高层次目标是在未来支持具有垃圾收集内存模型的语言)。

随着WebAssembly在浏览器中的出现,我们前面谈到的虚拟机现在将加载和运行两种类型的代码–JavaScript和WebAssembly。
不同的代码类型可以根据需要(as required)相互调用–WebAssembly的JavaScript API用可以正常调用的JavaScript函数来包装导出的WebAssembly代码,而WebAssembly代码可以导入并同步调用正常的JavaScript函数。事实上,WebAssembly代码的基本单位被称为模块,WebAssembly模块在许多方面与ES模块对称。

WebAssembly关键概念

要了解WebAssembly如何在浏览器中运行,需要几个关键概念。所有这些概念都在WebAssembly的JavaScript API中得到了1:1的反映。

  • 模块(Module)。代表一个WebAssembly二进制文件,已经被浏览器编译成可执行的机器代码。模块是无状态的(stateless),因此,像Blob一样,可以明确地在窗口和工作者之间共享(通过postMessage())。一个模块就像ES模块一样声明导入和导出。
  • 内存(Memory)。一个可调整大小的ArrayBuffer,包含由WebAssembly的底层(low-level)内存访问指令(access instructions)读取和写入的线性阵列。
  • 表(Table)。一个可调整大小的类型化的(typed)引用数组(例如函数),否则不能作为原始字节存储在Memory中(出于安全和可移植性的原因)。
  • 实例(Instance)。一个模块与它在运行时使用的所有状态配对,包括内存、表和一组导入值。一个实例就像一个ES模块,它已经被加载到一个特定的全局中,并带有一组特定的导入(imports)。
    PS:
    Blob: Blob(Binary Large Object)表示二进制类型的大对象。在数据库管理系统中,将二进制数据存储为一个单一个体的集合。Blob 通常是影像、声音或多媒体文件。在 JavaScript 中 Blob 类型的对象表示不可变的类似文件对象的原始数据。
    postMessage:window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为 https),端口号(443 为 https 的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。

JavaScript API为开发者提供了创建模块、内存、表格和实例的能力。给定一个WebAssembly实例,JavaScript代码可以同步调用它的出口(exports),这些出口被暴露为正常的JavaScript函数。任意的JavaScript函数也可以被WebAssembly代码同步调用,通过传递这些JavaScript函数作为WebAssembly实例的导入(imports)。

由于JavaScript可以完全控制WebAssembly代码的下载、编译和运行,JavaScript开发者甚至可以把WebAssembly看作只是一个有效生成高性能函数的JavaScript功能。
在未来,WebAssembly模块将像ES模块一样可以加载(使用

如何在自己的程序中使用WebAssembly

上面我们谈到了WebAssembly添加到Web平台的原始基元(raw primitives):代码的二进制格式和用于加载和运行这种二进制代码的API。现在我们来谈谈如何在实践中使用这些基元。
WebAssembly生态系统正处于萌芽阶段;今后无疑会有更多的工具出现。现在,有四个主要的切入点:

  • Emscripten移植C/C++应用程序。
  • 直接在汇编层面(assembly level)上编写或生成WebAssembly。
  • 编写Rust应用程序并将WebAssembly作为其输出目标。
  • 使用AssemblyScript,它看起来类似于TypeScript,并编译成WebAssembly二进制。

对于每个切入点概述:

移植C/C++程序

创建WASM代码的众多选择中,其中有两种常见的方式,一是在线WASM汇编器,二是Emscripten。有许多在线WASM汇编器的选择,如:

  • WasmFiddle
  • WasmFiddle++
  • WasmExplorer
    对于那些想知道从哪里开始的人来说,这些都是很好的资源,但它们缺乏Emscripten的一些工具(tooling)和优化(optimizations)。

Emscripten工具能够接受几乎所有(just about any)的C/C++源代码,并将其编译成一个.wasm模块,加上必要的JavaScript "胶水 "代码(“glue” code)来加载和运行该模块,以及一个HTML文档来显示代码的结果。
Emscripten 工作流程
简而言之(In a nutshell),这个过程是这样的:

  1. Emscripten首先将C/C++输入clang+LLVM, 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胶合代码。

Note: There are future plans to allow WebAssembly to call Web APIs directly.(未来的发展)

JavaScript的胶合代码并不像你想象的那样简单。首先,Emscripten实现了流行的C/C++库,如SDL、OpenGL、OpenAL和POSIX的一部分。这些库是以Web API的形式实现的(These libraries are implemented in terms of Web APIs),因此每个库都需要一些JavaScript胶水代码来连接WebAssembly和底层(underlying)Web API。
所以胶水代码的一部分是实现C/C++代码所使用的各个库的功能。胶合代码还包含调用上述WebAssembly JavaScript APIs来获取、加载和运行.wasm文件的逻辑。

生成的HTML文档会加载JavaScript胶水文件,并将stdout写到<textarea>中。如果应用程序使用OpenGL,HTML还包含一个<canvas>元素,作为渲染目标。修改Emscripten的输出非常容易,可以把它变成你需要的任何web app。

你可以在emscripten.org上找到关于Emscripten的完整文档,还可以在Compiling from C/C++ to WebAssembly上找到实现工具链和将自己的C/C++应用编译到wasm的指南。

直接写WebAssembly 汇编指令

你想建立自己的编译器,或者自己的工具,或者做一个在运行时生成WebAssembly的JavaScript库?
与物理汇编语言一样,WebAssembly二进制格式也有文本表示–两者有1:1的对应关系。你可以用手写或生成这种格式,然后用几个WebAssembly文本到二进制的工具中的任何一个将其转换为二进制格式。
关于如何做到这一点的简单指南,请参阅我们的转换WebAssembly文本格式为wasm的文章

写Rust 目标的WebAssembly

由于Rust WebAssembly工作组的不懈努力,编写Rust代码并编译到WebAssembly上也是可能的。你可以从安装必要的工具链开始,将一个Rust程序样本编译成WebAssembly的npm包,并在我们的Rust到WebAssembly的编译文章中使用这个样本。

使用AssemblyScript

对于那些想尝试WebAssembly而不需要学习C或Rust的细节,停留在TypeScript这样熟悉的语言中的网络开发者来说,AssemblyScript将是最好的选择。AssemblyScript将TypeScript的严格变体编译成WebAssembly,允许Web开发者继续使用他们熟悉的TypeScript兼容工具–如Prettier、ESLint、VS Code intellisense等。你可以在https://www.assemblyscript.org/ 上查看它的文档。

总结

学习一的内容提供了WebAssembly的概述,解释了为什么WebAssembly这么有用,它如何适应web以及你怎么使用它,下一步开始着重学习利用Emscripten工具去编译C/C++代码。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值