第二章:web篇A 实现rust与javascript交互

凝霜月冷残-草木破白衣 2024-06-28 13:33:02 阅读 91

WebAssembly简介

WebAssembly(简称Wasm)是一种新型的编程语言,它可以在网页浏览器中运行。WebAssembly的设计目标是提供一种新的代码格式,使得开发者可以使用高级编程语言(如C、C++、Rust等)编写的程序在浏览器中直接运行,而无需转换成JavaScript。这样做的好处是可以提高应用程序的执行效率,因为WebAssembly代码可以直接在浏览器中运行,而无需经过JavaScript引擎的解释过程。

WebAssembly

WebAssembly的二进制格式比JavaScript文本文件小得多,因此下载速度更快,这在网速较低的情况下尤为重要。WebAssembly的解析和执行速度也更快,因为它是静态类型的,引擎在编译期间不需要类型推断,大多数优化都是在编译源代码期间,在浏览器执行之前进行的。此外,WebAssembly的内存管理类似于C和C++,不需要垃圾收集,这也有助于提高性能。

WebAssembly与JavaScript之间是一种协作互补的关系。WebAssembly可以在某些场景中弥补JavaScript性能不足的短板,而想要在Web浏览器中使用WebAssembly,我们也离不开相关JavaScript API提供的帮助。WebAssembly可以与JavaScript代码交互,这意味着开发者可以使用WebAssembly来处理需要更高计算能力的任务,例如图像处理、游戏和虚拟现实等。

JavaScript

WebAssembly的应用场景广泛,包括游戏开发、图形图像处理、音视频处理、非JavaScript程序的移植等。例如,Unity和Unreal Engine等游戏引擎已经支持将游戏引擎编译成Wasm格式,并在浏览器中运行。此外,WebAssembly还可以用于网页游戏、数据可视化、图像处理、图形渲染等图形图像领域,以及Web播放器、在线教育、视频会议、直播、点播等音视频领域。

总的来说,WebAssembly为Web应用程序提供了一种新的性能优化手段,使得开发者可以在保持Web应用程序的可移植性和安全性的同时,提高应用程序的执行效率。

web-sys简介

web-sys 是一个用于 Rust 编程语言的 crate,它提供了访问 Web API 的方式,使得 Rust 代码能够在浏览器环境中运行。通过 web-sys,Rust 开发者可以直接调用 JavaScript 的 Web API,从而实现与 HTML、CSS 和 JavaScript 的交互。

web-sys 允许 Rust 代码操作 DOM(文档对象模型),例如创建和修改 HTML 元素、处理事件等。此外,它还支持与 WebGL、Canvas、Audio、Video 等多媒体相关的 API,以及与网络通信相关的 API,如 Fetch API。

使用 web-sys 时,通常需要通过 wasm-bindgen crate 来进行绑定生成,以便在 Rust 代码中使用 JavaScript 的 Web API。wasm-bindgen 负责将 Rust 类型转换为 JavaScript 类型,并生成相应的绑定代码。

在使用 web-sys 时,开发者需要在 Cargo.toml 文件中声明依赖,并根据需要启用特定的功能(features)。例如,如果需要使用 console 对象,就需要在 features 中添加 console

web-sys 是构建 WebAssembly 应用程序时常用的工具之一,它有助于 Rust 代码与现代 Web 技术的无缝集成。

环境配置

安装rust编译器

安装nodejs二进制文件

! nodejs二进制下载后,选择存放目录后解压并配置环境变量

项目目录结构

代码案例:rust与javascript交互案例

./Cargo.toml

[workspace]

members = [

"rust_project",

]

./rust_project/Cargo.toml

[package]

name = "rust_project"

version = "0.1.6"

authors = ["name <name@163.com>"]

description = "A sample project with wasm-pack"

license = "MIT/Apache-2.0"

repository = "https://github.com/yourgithubusername/hello-wasm"

edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]

crate-type = ["cdylib"]

[dependencies]

wasm-bindgen = "0.2.92"

futures = { version = "0.3.30", features = ["thread-pool"] }

[dependencies.web-sys]

version = "0.3.69"

features = [

"console"

]

./rust_project/lib.rs

extern crate wasm_bindgen;

use wasm_bindgen::prelude::*;

//调用外部函数

#[wasm_bindgen]

extern {

pub fn alert(s: &str);

}

#[wasm_bindgen]

extern "C" {

// Use `js_namespace` here to bind `console.log(..)` instead of just

// `log(..)`

#[wasm_bindgen(js_namespace = console)]

fn log(s: &str);

// The `console.log` is quite polymorphic, so we can bind it with multiple

// signatures. Note that we need to use `js_name` to ensure we always call

// `log` in JS.

#[wasm_bindgen(js_namespace = console, js_name = log)]

fn log_u32(a: u32);

// Multiple arguments too!

#[wasm_bindgen(js_namespace = console, js_name = log)]

fn log_many(a: &str, b: &str);

}

// 提供外部调用的函数

#[wasm_bindgen]

pub fn greet(name: &str) {

alert(&format!("Hello, {}!", name));

}

#[wasm_bindgen]

pub fn add(a: i32, b: i32) -> i32 {

a + b

}

//web assembly初始化时自动执行

#[wasm_bindgen(start)]

pub fn run() {

bare_bones();

using_a_macro();

using_web_sys();

}

fn bare_bones() {

log("Hello from Rust!");

log_u32(42+58);

log_many("Logging", "many values!");

}

// Next let's define a macro that's like `println!`, only it works for

// `console.log`. Note that `println!` doesn't actually work on the wasm target

// because the standard library currently just eats all output. To get

// `println!`-like behavior in your app you'll likely want a macro like this.

macro_rules! console_log {

// Note that this is using the `log` function imported above during

// `bare_bones`

($($t:tt)*) => (log(&format_args!($($t)*).to_string()))

}

fn using_a_macro() {

console_log!("Hello {}!", "world");

console_log!("Let's print some numbers...");

console_log!("1 + 3 = {}", 1 + 3);

}

// And finally, we don't even have to define the `log` function ourselves! The

// `web_sys` crate already has it defined for us.

fn using_web_sys() {

use web_sys::console;

console::log_1(&"Hello using web-sys".into());

let js: JsValue = 4.into();

console::log_2(&"Logging arbitrary values looks like".into(), &js);

}

./web_project/index.js

const js = import("./node_modules/@name/rust_project/rust_project.js");

js.then((js) => {

js.greet("WebAssembly");

});

js.then((js) => {

const result = js.add("1, 2");

console.log(`The result from Rust is: ${result}`);

});

./web_project/index.html

<!doctype html>

<html>

<head>

<meta charset="utf-8" />

<title>hello-wasm example</title>

</head>

<body>

<script src="./index.js">

</script>

</body>

</html>

./web_project/package.json

{

"scripts": {

"serve": "webpack-dev-server"

},

"dependencies": {

"@name/rust_project": "^0.1.6"

},

"devDependencies": {

"webpack": "^4.47.0",

"webpack-cli": "^3.3.12",

"webpack-dev-server": "^3.11.3"

}

}

./web_project/package.config.js

const path = require("path");

module.exports = {

entry: "./index.js",

output: {

path: path.resolve(__dirname, "dist"),

filename: "index.js",

},

mode: "development",

};

执行方式

接下来,在命令行中运行 npm adduser:

bash

> npm adduser

Username: yournpmusername

Password:

Email: (this IS public) you@example.com

你需要完善你的用户名,密码和邮箱。如果成功了,你将会看到:

bash

Logged in as yournpmusername on https://registry.npmjs.org/.

构建包

现在我们已经完成了所有配置项,开始构建吧!在命令行输入以下命令:

bash

wasm-pack build --scope name

把我们的包发布到 npm

把我们的新包发布到 npm registry:

bash

cd pkg

npm publish --access=public

让我们离开pkg目录,并创建一个新目录site,尝试以下操作:

bash

cd ../..

mkdir web_project

cd web_project

npm install

npm run serve

 这将启动一个 Web 服务器。访问 http://localhost:8080,你应该会在屏幕上看到一个内容为 Hello, WebAssembly! 的警告框。我们已经成功地从 JavaScript 调用了 Rust,并从 Rust 调用了 JavaScript。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。