#include // 递归方式计算斐波那契数列的第n个数
int fibonacci(int n) {
if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2);
}
int main() {
int n; std::cout << "请输入斐波那契数列的项数:"; std::cin >> n; std::cout << fibonacci(n); return 0;
}
g++ fib.cpp -o fib && ./fib
Emscripten 是一个完整的 WebAssembly 编译器工具链,使用 LLVM,特别关注速度、大小和 Web 平台。
这里又引入了一个新概念:LLVM。LLVM(Low-Level Virtual Machine)
是一个开源的编译器基础设施项目,它提供了一组模块化的编译器和工具,用于构建、优化和执行程序。LLVM 最初是为编译器开发而设计的,但它已经演变成一个通用的编译器基础设施,可以用于多种编程语言和领域。
LLVM 的主要组件包括:
- 前端:LLVM 支持多种编程语言的前端,包括 C/C++、Rust、Swift、Python 等。这些前端将源代码转换成一种称为
LLVM IR(Intermediate Representation)
的中间代码。 - 中间表示(LLVM IR):LLVM IR 是一种类似汇编语言的中间代码,它是 LLVM 的核心。所有支持的编程语言都被翻译成 LLVM IR,这样可以在后续的优化阶段进行通用的编译器优化。
- 优化器:LLVM 包含强大的优化器,它可以在不改变程序语义的情况下提高代码的性能。这些优化包括死代码删除、内联函数、循环优化等。类似 JS 构建领域的代码压缩器。
- 后端:LLVM 还包括用于不同目标架构的后端代码生成器。这意味着你可以使用 LLVM 来生成针对不同硬件架构的机器码,从而实现跨平台的编译。
- 工具:LLVM 提供了许多辅助工具,用于调试、分析和测试代码。
对于软件工程师来说,LLVM 在编译器开发、代码优化和跨平台编译方面具有重要意义。它还被广泛用于编程语言的实现和各种编译器项目中。
Emscripten 安装
官网有多种安装方式,这里我们使用推荐的 emsdk
。
我们将使用了三方模块的 c++ 代码,编译为了 wasm,但是有个关键问题没解决:如何将 JS 与 wasm 当中的数据互传?
wasm 可以理解成独立工作的 Worker 线程,但是 JS 的线程模型和 Java 这种多线程模型的语言不同,JS 内创建的一些对象、字符串等都存在于 V8 等虚拟机的堆内存里,外部线程无法直接操作。而 Java 为代表的多线程语言,线程共享同一块内存区域,可以任意读写(但是存在并发问题)。
斐波那契函数的示例,不存在此问题,因为 wasm 虚拟机本身就支持 int 32/int64/float 等整数、浮点数数据类型的传递。
可以看到,上述流程当中,最关键的就 2 个核心要素:
- JS 与 wasm 互传的数据只能是整数、浮点数
- wasm 有暴露共享的 ArrayBuffer 供 JS 操作,以达到互传数据的目的
对于上线的项目:
1、使用wasm由于体积大小的问题,不要放在main.js里面去打包,会阻塞白屏时间
2、采用异步加载的方式
3、对于编解码或者耗资源的情况,建议放到web worker中进行实例化,在处理业务逻辑