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

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。

相关推荐
麒麟而非淇淋4 分钟前
AJAX 入门 day3
前端·javascript·ajax
茶茶只知道学习17 分钟前
通过鼠标移动来调整两个盒子的宽度(响应式)
前端·javascript·css
蒟蒻的贤19 分钟前
Web APIs 第二天
开发语言·前端·javascript
清灵xmf23 分钟前
揭开 Vue 3 中大量使用 ref 的隐藏危机
前端·javascript·vue.js·ref
蘑菇头爱平底锅25 分钟前
十万条数据渲染到页面上如何优化
前端·javascript·面试
su1ka11128 分钟前
re题(35)BUUCTF-[FlareOn4]IgniteMe
前端
测试界柠檬30 分钟前
面试真题 | web自动化关闭浏览器,quit()和close()的区别
前端·自动化测试·软件测试·功能测试·程序人生·面试·自动化
多多*31 分钟前
OJ在线评测系统 登录页面开发 前端后端联调实现全栈开发
linux·服务器·前端·ubuntu·docker·前端框架
2301_8010741531 分钟前
TypeScript异常处理
前端·javascript·typescript
小阿飞_33 分钟前
报错合计-1
前端