在 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
现在我们可以安装所有依赖项并启动服务器:
$ cd wasm_react
$ yarn install
$ yarn start
之后,您可以访问http://localhost:8080并检查它是否有效。
创建画布组件
接下来我们要做的就是创建一个新的带有画布的 React 组件,并添加绘图功能。
对于我们的新组件,我们可以创建新文件:
$ touch src/canvas.js
并输入以下代码:
// 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;
该组件使用来自的参数创建画布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();
现在您可以进入浏览器并检查是否可以看到黑色矩形:
绘制分形
接下来我们要绘制的是极其美丽的曼德布洛特集。首先,我们将使用 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;
}
//.....
之后,我们可以添加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);
}
}
}
经过这样的改变,你就可以在页面上看到曼德布洛特集:
看起来很棒,不是吗?
在 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;
}
我们的函数在编译后有一个奇怪的名字:_Z10mandelIterffi
。我们将在我们的 JavaScript 代码中使用这个名字。
编译完成后,我们可以下载并将文件放入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 {
下一步是更新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);
}
}
});
}
现在,为了在画布上绘图,我们使用在 WebAssembly 中实现的函数。
您可以操纵变量mag
,panX
并panY
创建另一种形式的分形:
您可以在我的存储库中找到所有代码。
最初发表于brightinventions.pl
作者:Ivan Menshykov,Bright Inventions 软件开发人员
鏂囩珷鏉ユ簮锛�https://dev.to/brightdevs/using-web assembly-with-react-1led