Angular中使用C程序
kelvin 发布于 2022-05-23

翻译:Using Web Assembly to speed up your Angular Application

作者:Lukas Marx

Web程序集可以由多种语言生成,如C、C++或Rust。甚至还有一个将TypeScript编译成Web程序集的实验项目。对于本教程,我们将保持其简单性并编译一个非常基本的C程序。

创建新的Angular项目

我们可以使用angular cli执行此操作:

ng new angular-wasm

我们还需要Web程序集JavaScript API的类型。让我们安装它们:

npm install @types/webassembly-js-api --dev --save

将C编译为WASM

在编译任何东西之前,我们需要先创建C程序。为此,请继续在项目根目录中创建一个名为“wasm”的文件夹。在该文件夹中,创建一个名为“fibonacci.c”的文件。没错!我们的示例将计算任何数字的斐波那契数,因为这是一项非常昂贵的任务。尤其是对于更高的数字。

int fibonacci(int n)
{
    if (n == 0 || n == 1)
        return n;
    else
        return (fibonacci(n - 1) + fibonacci(n - 2));
}

向JavaScript公开函数

我们在这里要做的是使斐波那契函数可以从JavaScript代码中调用。因此,我们需要用一种特殊的装饰物来标记它。对于这个decorator,我们需要包括emscripten.h之后,程序如下所示:

#include <emscripten.h>

int EMSCRIPTEN_KEEPALIVE fibonacci(int n)
{
    if (n == 0 || n == 1)
        return n;
    else
        return (fibonacci(n - 1) + fibonacci(n - 2));
}

将C编译为Web程序集(WASM)

要使用此函数,我们需要先将其编译为Web Assembly,因为浏览器不理解C。为此,我们使用之前安装的编译器。执行此操作的命令如下所示:

emcc wasm/fibonacci.c -Os -s WASM=1 -s MODULARIZE=1 -o wasm/fibonacci.js

Os选项定义了执行的优化级别。我们这里用的是很高的等级。

除了WASM之外,编译器还将生成一个JavaScript文件。该文件包含一些胶水代码,用于处理WASM和JavaScript之间的通信。使用module=1选项,我们告诉编译器将代码包装到模块中。这样,在我们的angular应用程序中消费就容易多了。

该命令的结果应该是两个新文件:fibonacci.js和fibonacci.wasm。

在Angular Service中包装Web Assembly

现在我们可以在角度中使用WASM函数。这些实用风格的函数的最佳位置是在单独的服务中。因此,我们将创建一个名为WasmService的新服务。

要让angular cli为我们生成该服务,请使用以下命令:

ng generate service wasm

不幸的是,使用WASM模块并不像使用普通JavaScript模块那么容易。

我们不仅需要导入WASM JavaScript粘合代码模块

src/app/wasm.service.ts

import * as Module from './../../wasm/fibonacci.js'

但是还必须使用文件加载器导入was文件本身

import '!!file-loader?name=wasm/fibonacci.wasm!../../wasm/fibonacci.wasm';

不幸的是,这样WASM文件就不包括在捆绑包中,而是作为单独的文件提供。

实例化Web程序集

要在运行时使用WASM文件,必须从提供的URL获取该文件并将其转换为字节数组。

为此,我们在服务内部创建了一个名为“InstanceWasm”的新方法。

src/app/wasm.service.ts

private async instantiateWasm(url: string){
  // fetch the wasm file
  const wasmFile = await fetch(url);

  // convert it into a binary array
  const buffer = await wasmFile.arrayBuffer();
  const binary = new Uint8Array(buffer);

  // create module arguments
  // including the wasm-file
  const moduleArgs = {
    wasmBinary: binary,
    onRuntimeInitialized: () => {
      // TODO
    }
  };

  // instantiate the module
  this.module = Module(moduleArgs);
}

请注意,我们还需要在服务上创建一个名为“module”的属性。此属性将包含模块及其所有函数,包括斐波那契函数。

现在,我们可以在服务的构造函数中调用该方法:

src/app/wasm.service.ts

constructor() {
  this.instantiateWasm('wasm/fibonacci.wasm');
}

为了方便地将斐波那契函数提供给角度分量,我们将在服务中创建一个同名的方法。

在该方法内部,我们只是调用WASM函数。

src/app/wasm.service.ts

public fibonacci(input: number): number{
 return this.module._fibonacci(input)
}

 

kelvin
关注 私信
文章
92
关注
0
粉丝
0