在 React 中使用 WebAssembly

2025-06-08

在 React 中使用 WebAssembly

WebAssembly (WASM) 是浏览器中可执行代码的二进制格式。
在本文中,我们将使用 React 库创建一个简单的 Web 应用程序,将部分 JavaScript 代码编写并编译为 WASM,然后将其链接到该应用程序。

我们需要一个包含 React 库的极简应用程序。我不会详细描述如何从头开始创建它,您可以阅读文章《极简 React + Webpack 4 + Babel 配置》 。此仓库中的应用程序足以满足我们的需求。

准备

要开始使用最小的 React 应用程序,我们可以克隆存储库:

$ git clone git@github.com:rwieruch/minimal-react-webpack-babel-setup.git wasm_react 
Enter fullscreen mode Exit fullscreen mode

现在我们可以安装所有依赖项并启动服务器:

$ cd wasm_react
$ yarn install
$ yarn start
Enter fullscreen mode Exit fullscreen mode

之后,您可以访问http://localhost:8080并检查它是否有效。

创建画布组件

接下来我们要做的就是创建一个新的带有画布的 React 组件,并添加绘图功能。

对于我们的新组件,我们可以创建新文件:

$ touch src/canvas.js
Enter fullscreen mode Exit fullscreen mode

并输入以下代码:

// src/canvas.js
import React, {Component} from "react";

class Canvas extends Component {

  componentDidMount() {
    let canvas = this.refs.canvas.getContext('2d');
    canvas.fillRect(0, 0, 100, 100);
  }

  render() {
    return (
        <canvas ref="canvas" width={this.props.width} height={this.props.height}/>
    )
  }
}

export default Canvas;
Enter fullscreen mode Exit fullscreen mode

该组件使用来自的参数创建画布props,之后您应该在画布中看到一个黑色矩形。

为了渲染新组件,我们可以将其添加到src/index.js

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';

import Canvas from './canvas';

const title = 'My Minimal React Webpack Babel Setup';

ReactDOM.render(
  <Canvas height={500} width={500} />,
  document.getElementById('app')
);

module.hot.accept();
Enter fullscreen mode Exit fullscreen mode

现在您可以进入浏览器并检查是否可以看到黑色矩形

画布上的黑色矩形

绘制分形

接下来我们要绘制的是极其美丽的曼德布洛特集。首先,我们将使用 JavaScript 实现它,然后再用 WebAssembly 重新实现它。更多理论背景,请参阅这篇文章。我刚刚从这篇文章中找到了主要函数。

现在我们可以将该mandelIter函数添加到我们的 Canvas 组件中:

// scr/canvas.js
class Canvas extends Component {

//.....

mandelIter(x, y, maxIter) {
  let r = x;
  let i = y;
  for (let a = 0; a < maxIter; a++) {
    let tmpr = r * r - i * i + x;
    let tmpi = 2 * r * i + y;

    r = tmpr;
    i = tmpi;

    if (r * i > 5) {
      return a/maxIter * 100;
    }
  }

  return 0;
}

//.....
Enter fullscreen mode Exit fullscreen mode

之后,我们可以添加componentDidMount两个循环来遍历画布中的所有像素。

更新后的功能:

// src/canvas.js
componentDidMount() {
  let canvas = this.refs.canvas.getContext('2d');
  let mag = 200;
  let panX = 2;
  let panY = 1.25;
  let maxIter = 100;

  for (let x = 10; x < this.props.height; x++)  {
    for (let y = 10; y < this.props.width; y++)  {
      let m = this.mandelIter(x/mag - panX, y/mag - panY, maxIter);
      canvas.fillStyle = (m === 0) ? '#000' : 'hsl(0, 100%, ' + m + '%)'; 
      canvas.fillRect(x, y, 1,1);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

经过这样的改变,你就可以在页面上看到曼德布洛特集:

曼德布洛特集分形在画布上绘制

看起来很棒,不是吗?

在 WebAssembly 中实现

现在我们可以mandelIter用 WebAssembly 实现一个函数了。我们可以用 C++、Rust 或 Go 来实现。不过这里我们将使用 C++ 和一个在线编译器WebAssembly Explorer

在C++中实现的函数mandelIter

float mandelIter(float x, float y, int maxIter) {
  float r = x;
  float i = y;
  for (int a = 0; a < maxIter; a++) {
    float tmpr = r * r - i * i + x;
    float tmpi = 2 * r * i + y;

    r = tmpr;
    i = tmpi;

    if (r * i > 5) {
      return a/(float) maxIter * 100;
    }
  }

  return 0;
}
Enter fullscreen mode Exit fullscreen mode

我们的函数在编译后有一个奇怪的名字:_Z10mandelIterffi。我们将在我们的 JavaScript 代码中使用这个名字。

浏览器中的 WebAssembly Explorer

编译完成后,我们可以下载并将文件放入src文件夹中。我将其命名为fractal.wasm

要在 React 中使用 wasm,你只需要向 -component 添加 import 即可Canvas

// src/canvas.js
import React, {Component} from "react";

const wasm = import("./fractal.wasm");

class Canvas extends Component {
Enter fullscreen mode Exit fullscreen mode

下一步是更新componentDidMount函数:

// src/canvas.js

componentDidMount() {
  wasm.then(wasm => {
    const mandelIterWASM = wasm._Z10mandelIterffi;
    let canvas = this.refs.canvas.getContext('2d');
    let mag = 200;
    let panX = 2;
    let panY = 1.25;
    let maxIter = 100;

    for (let x = 10; x < this.props.height; x++)  {
      for (let y = 10; y < this.props.width; y++)  {
        // let m = this.mandelIter(x/mag - panX, y/mag - panY, maxIter);
        let m = mandelIterWASM(x/mag - panX, y/mag - panY, maxIter);
        canvas.fillStyle = (m === 0) ? '#000' : 'hsl(0, 100%, ' + m + '%)'; 
        canvas.fillRect(x, y, 1,1);
      }
    }
  });
}

Enter fullscreen mode Exit fullscreen mode

现在,为了在画布上绘图,我们使用在 WebAssembly 中实现的函数。

您可以操纵变量magpanXpanY创建另一种形式的分形:

您可以在我的存储库中找到所有代码

最初发表于brightinventions.pl

作者:Ivan Menshykov,Bright Inventions 软件开发人员

叽叽喳喳

鏂囩珷鏉ユ簮锛�https://dev.to/brightdevs/using-web assembly-with-react-1led
PREV
为了提高您的技术技能,成为一名概念收集者!
NEXT
不要成为模型开发人员