TypeScript 如何利用 WebAssembly 加速?

目前 TypeScript 类型编译后是完全擦除的,什么时候我们能用上TypeScript 编译到 WebAssembly ,让 jit 更快, 让手…
关注者
21
被浏览
14,094

2 个回答

WebAssembly ,也称为 Wasm,是为 Web 创建的二进制格式。它允许通过从常规 JavaScript 访问的相同 Web API 访问浏览器功能。WebAssembly 的最大亮点之一是效率和速度,在不po浏览器的权限安全策略,以接近原生的性能速度安全地运行。

尽管具有 Web 特性,但 WebAssembly 也可以在非 Web 模式下运行,例如服务器、物联网设备、移动/桌面应用程序,考虑到某些 Web 功能将不可用。

目前四种主要浏览器(Firefox、Chrome、Safari 和 Edge)都支持 WebAssembly,关于WebAssembly的介绍、优势等信息可以查阅《 再次认识 WebAssembly 》和《 快速认识 WebAssembly 》,本文主要内容是构建一个应用。

编写 AssemblyScript

AssemblyScript 代码看起来类似于 TypeScript。如果不熟悉它,请不要担心,基本上熟悉JavaScript也能看懂 TypeScript。

通过以下示例了解相应的区别:

这是一个不可移植的 AssemblyScript 代码,使用 TypeScript 并非 100% 准确:

let someFloat: f32 = 1.5
let someInt: i32 = <i32>someFloat

在 TypeScript 中,所有数字类型都是数字的别名,因此这些数字类型之间没有区别。

使用 AssemblyScript 编译器生成的可移植 TypeScript 代码将是:

let someFloat: f32 = 1.5
let someInt: i32 = i32(someFloat)

使用常规 typescript 编译器编译代码后,结果将是:

var someFloat = 1.5
var someInt = someFloat | 0

可以通过两种不同的方式编写 AssemblyScript:

  • 标准库
  • 低级 WebAssembly

这些方法并不相互排斥,可以根据需要将它们混合使用。

标准库

AssemblyScript 提供了一个类似于 JavaScript 的 标准库 ,类似于 JavaScript 使用的标准库。

// It takes in two 32-bit integer values
// And returns a 32-bit integer value.
export function addInteger(a: i32, b: i32): i32 {
  return a + b;
}

低级 WebAssembly

在某些情况下,需要编写低级的WebAssembly。WebAssembly中前面函数的摘录如下所示:

(func $assembly/index/addInteger (param $0 i32) (param $1 i32) (result i32)
  local.get $0
  local.get $1
  i32.add
 )

应该避免使用非严格的 TypeScript 代码,因为并非所有代码都是有效的 AssemblyScript 代码。阅读有关 TypeScript 严格模式的 更多信息

编写第一个AssemblyScript

开始之前需要确保机器上安装了 Node.js 最新的 LTS 版本,可以从 nodejs.org 获取。使用旧版本的 Node.js 会导致使用 AssemblyScript 编译器出错。第一个简单的 AssemblyScript,可以参阅《 再次认识 WebAssembly 》。

创建基于浏览器的钟摆

好吧,在浏览器中绘制钟摆并不是非常需要使用 Wasm,但主要目的是来了解如何使用 Wasm 来依赖于动画和绘制钟摆所需的数学计算:

Wasm 代码将负责钟摆的位置计算,有两个主要函数:

init 函数

export function init(
    startPositionX: f64,
    amplitude: u32,
    w: u32,
    h: u32
): void {
    angle = 0;
    var needed = (<i32>((w * h * sizeof<i32>() + 0xffff) & ~0xffff)) >>> 16;
    var actual = memory.size();
    if (needed > actual) memory.grow(needed - actual);
    pendulum = new Pendulum(startPositionX, amplitude);
}

该函数通过将变量存储在名为 Pendulum 的类对象中来负责变量的初始化;这个函数的另一个职责是负责内存分配;它使用配置的画布宽度和高度来计算所需的内存。如果没有正确分配内存, Wasm 可能会失败,更多内存管理可以点击 这里阅读

move 函数

export function move(): void {
    angle += 10;
    if (angle == 360 || angle > 360) {