This example connects to an echo server on wss://echo.websocket.org, sends a ping message, and receives the response.
_ wasm-bindgen Guide{target="_blank"}
web-sys: request-animation-frame{target="_blank"}
setup the project
cargo new request-animation-frame --lib
cd request-animation-frame
mkdir -p www/js www/html
cargo add wasm-bindgen
- Edit Cargo.toml
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.89"
[dependencies.web-sys]
version = "0.3.66"
features = [
'Document',
'Element',
'HtmlElement',
'Node',
'Window',
]
The code
- index.html
<!doctype html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
<title>request-animation-frame: nobundle</title>
</head>
<body>
<p>A greeting from rust looks like...</p>
<script type="module" src="../js/index.js"></script>
</body>
</html>
- index.js
import init from '../pkg/request_animation_frame.js';
async function run() {
const wasm = await init().catch(console.error);
}
run();
Note: request-animation-frame
becomes request_animation_frame
- Rust side
#![allow(unused)] fn main() { // src/lib.rs use std::cell::RefCell; use std::rc::Rc; use wasm_bindgen::prelude::*; fn window() -> web_sys::Window { web_sys::window().expect("no global `window` exists") } fn request_animation_frame(f: &Closure<dyn FnMut()>) { window() .request_animation_frame(f.as_ref().unchecked_ref()) .expect("should register `requestAnimationFrame` OK"); } fn document() -> web_sys::Document { window() .document() .expect("should have a document on window") } fn body() -> web_sys::HtmlElement { document().body().expect("document should have a body") } // This function is automatically invoked after the wasm module is instantiated. #[wasm_bindgen(start)] fn run() -> Result<(), JsValue> { // Here we want to call `requestAnimationFrame` in a loop, but only a fixed // number of times. After it's done we want all our resources cleaned up. To // achieve this we're using an `Rc`. The `Rc` will eventually store the // closure we want to execute on each frame, but to start out it contains // `None`. // // After the `Rc` is made we'll actually create the closure, and the closure // will reference one of the `Rc` instances. The other `Rc` reference is // used to store the closure, request the first frame, and then is dropped // by this function. // // Inside the closure we've got a persistent `Rc` reference, which we use // for all future iterations of the loop let f = Rc::new(RefCell::new(None)); let g = f.clone(); let mut i = 0; *g.borrow_mut() = Some(Closure::new(move || { if i > 300 { body().set_text_content(Some("All done!")); // Drop our handle to this closure so that it will get cleaned // up once we return. let _ = f.borrow_mut().take(); return; } // Set the body's text content to how many times this // requestAnimationFrame callback has fired. i += 1; let text = format!("requestAnimationFrame has been called {} times.", i); body().set_text_content(Some(&text)); // Schedule ourself for another requestAnimationFrame callback. request_animation_frame(f.borrow().as_ref().unwrap()); })); request_animation_frame(g.borrow().as_ref().unwrap()); Ok(()) } }
build and serve
wasm-pack build --target web --no-typescript --out-dir www/pkg
http www
open index.html
firefox http://localhost:8000/html/
What's next?
Next example: A Simple Paint Program -->