这是 3 部分系列中的第 1 篇文章
- 使用 JavaScript 创建 WebAssembly 模块实例
- WebAssembly 中的内存(以及为什么它比你想象的更安全)
- WebAssembly 表导入… 它们是什么?
WebAssembly 是一种 在 Web 上运行代码的新方式。有了它,你可以用 C 或 C++ 等语言编写模块并在浏览器中运行它们。
目前,模块还不能独立运行。预计这种情况会随着 ES 模块支持在浏览器中的出现而改变。一旦到位,WebAssembly 模块将 很可能以与其他 ES 模块相同的方式加载,例如使用 <script type="module">
。
但目前,你需要使用 JavaScript 启动 WebAssembly 模块。这将创建一个模块实例。然后你的 JavaScript 代码可以调用该 WebAssembly 模块实例上的函数。
例如,让我们看看 React 如何实例化一个 WebAssembly 模块。(你可以在这个视频中了解有关 React 如何使用 WebAssembly 的更多信息。)
当用户加载页面时,它将以相同的方式开始。
浏览器将下载 JS 文件。此外,还会获取一个 .wasm 文件。其中包含 WebAssembly 代码,它是二进制的。
我们需要加载这些文件中的代码才能运行它。首先是 .js 文件,它加载 React 的 JavaScript 部分。然后该 JavaScript 将创建一个 WebAssembly 模块的实例… 协调器。
为此,它将调用 WebAssembly.instantiate
。
让我们仔细看看它。
我们传递给 WebAssembly.instantiate
的第一件事将是我们从 .wasm 文件中获取的二进制代码。这就是模块代码。
因此,我们将二进制文件提取到一个缓冲区中,然后将其传递进去。
引擎将开始将模块代码编译成特定于其运行的机器的东西。
但我们不想在主线程上执行此操作。我之前说过主线程就像一个全栈开发人员,因为它处理 JavaScript、DOM 和布局。我们不想在编译模块时阻塞主线程。因此,WebAssembly.instantiate
返回的是一个承诺。
这使得主线程可以回到其他工作。主线程知道一旦编译器完成编译此模块,它将通过承诺收到通知。该承诺将为它提供实例。
但是,编译后的模块并不是创建实例所需的唯一东西。我认为模块就像一本说明书。
实例就像一个试图用说明书制作东西的人。为了制作该东西,他们还需要原材料。他们需要可以操作的东西。
这就是 WebAssembly.instantiate
的第二个参数的用武之地。这就是导入对象。
我认为导入对象就像一个装有原材料的盒子,就像你从宜家买到的那样。实例使用这些原材料(这些导入)来构建东西,如指令所指。正如说明手册预期使用一组特定的原材料一样,每个模块都预期使用一组特定的导入。
因此,当你实例化一个模块时,你会传递一个包含这些导入的导入对象。每个导入可以是以下四种导入之一
- 值
- 函数闭包
- 内存
- 表
值
它可以包含值,这些值基本上是全局变量。WebAssembly 目前支持的唯一类型是整数和浮点数,因此值必须是这两个类型之一。这将随着 WebAssembly 规范中添加更多类型而发生变化。
函数闭包
它还可以包含函数闭包。这意味着你可以传入 JavaScript 函数,WebAssembly 然后可以调用这些函数。
这特别有用,因为在当前版本的 WebAssembly 中,你不能直接调用 DOM 方法。直接 DOM 访问已列入 WebAssembly 路线图,但尚未成为规范的一部分。
你可以做的是传入一个 JavaScript 函数,它可以按照你需要的 방식与 DOM 交互。然后 WebAssembly 只需调用该 JS 函数即可。
内存
另一种导入是内存对象。这个对象使 WebAssembly 代码能够模拟手动内存管理。内存对象的概念让人困惑,所以我在这篇 另一篇文章(本系列的下一篇文章)中更深入地讨论了它。
表
最后一种类型的导入也与安全性有关。它被称为表。它使你能够使用称为函数指针的东西。同样,这有点复杂,所以我在这篇 本系列的第三部分 中进行了解释。
这些是你可以为实例配备的不同类型的导入。
为了返回实例,从 WebAssembly.instantiate
返回的承诺将被解决。它包含两件事:实例和编译后的模块(分别)。
拥有编译后的模块的好处在于,你可以快速启动同一模块的其他实例。你所要做的就是将模块作为 source
参数传递进去。模块本身没有任何状态(所有状态都附加到实例上)。这意味着实例可以共享编译后的模块代码。
你的实例现在已经完全准备就绪,可以开始工作了。它有它的说明手册,即编译后的代码,以及它所有的导入。现在你可以调用它的方法了。
在接下来的两篇文章中,我们将深入探讨 内存导入 和 表导入。
关于 Lin Clark
Lin 在 Mozilla 的高级开发部门工作,专注于 Rust 和 WebAssembly。
3 则评论