iTranslated by AI
Implementing Sleep in WebAssembly: Rust Journey (8)
seems like wasm-timer::Delay can be used
Related Articles:
- How to integrate blazingly fast esbuild into rollup.js
- The issue of Rust's image::load_from_memory being too slow
Previous articles in the Rust Chronicles series
- Developing a Windows development environment with WSL2: Rust Chronicles (1)
- Knocking on the door of WebAssembly with wasmer: Rust Chronicles (2)
- Calling WebAssembly functions from JavaScript: Rust Chronicles (3)
- Running WebAssembly with TypeScript and Rollup: Rust Chronicles (4)
- With Svelte, WebAssembly, TypeScript, and Rollup: Rust Chronicles (5)
- Is the WASM size too big?: Rust Chronicles (6)
- Researching WebAssembly multithreading crates: Rust Chronicles (7)
- Sleep in WebAssembly: Rust Chronicles (8) ← You are here
I wonder how I can distinguish if something is usable in Wasm.
------------------- ↓ Introduction starts here ↓-------------------
To create a sample of asynchronous processing, I wanted to represent time-delayed operations by sleeping for a random duration on WebAssembly.
Is this what it looks like in code?
use std::time::Duration;
use std::{thread, time};
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn sleep_millis(numbers: u16) {
let millis: u64 = u64::from(numbers);
let ten_millis: Duration = time::Duration::from_millis(millis);
thread::sleep(ten_millis);
}
When I run this,
1a8d8036:0x15b9 Uncaught (in promise) RuntimeError: unreachable
at <anonymous>:wasm-function[5]:0x15b9
at <anonymous>:wasm-function[13]:0x1876
at <anonymous>:wasm-function[11]:0x1823
at <anonymous>:wasm-function[12]:0x1851
at sleep_millis (<anonymous>:wasm-function[7]:0x1710)
at Object.sleep_millis (index.js:8)
at App.svelte:7
at Generator.next (<anonymous>)
at App.svelte:1
at new Promise (<anonymous>)
If I remove the sleep line, the error disappears.
(゚_゚) Are you kidding me...
Looking into it, it works fine when running in Rust, but it seems impossible to simply use sleep when running on WebAssembly.
There were even people doing acrobatic things like loading JavaScript.
That's fine for a sample, but it's not realistic for actual use.
When I looked for something good, I found something that seems quite usable.
That is
wasm-timer::Delay
ヾ(・ω<)ノ" 三三三● ⅱⅲ Rolling♪
------------------- ↓ Main content starts here ↓-------------------
Creating the project
Create a project from a template with a combination of rollup.js + WebAssembly.
The template's package versions are outdated, so I will update them to the latest.
cargo install cargo-edit wasm-pack
npx degit wasm-tool/rollup-plugin-rust/example wasm-sleep
cd wasm-sleep
npx npm-check-updates -u
npm i
cargo upgrade
cargo check
Installing additional packages
- js-sys
- Access parameters on the JavaScript side
- Necessary for asynchronous processing
- wasm-bindgen-futures
- Bridges Rust Futures and JavaScript Promises
- Necessary for asynchronous operations
- wasm-timer
- Timer-related package
- parking_lot
- Cuts off unnecessary code generated when using timers
cargo add js-sys wasm-bindgen-futures wasm-timer
cargo add parking_lot --features wasm-bindgen
Creating a timer function
Implementation to take input in msec and return a Promise
use std::time::Duration;
use wasm_bindgen::prelude::*;
use wasm_timer::Delay;
#[wasm_bindgen]
pub async fn sleep_millis(numbers: u16) -> js_sys::Promise {
let millis: u64 = u64::from(numbers);
Delay::new(Duration::from_millis(millis)).await.unwrap();
let promise = js_sys::Promise::resolve(&numbers.into());
return promise;
}
Front-end implementation
Prepare the front-end to verify the sleep operation.
By displaying the execution time in the console, check if it stops for 5 seconds with sleep_millis.
import wasm from "../Cargo.toml";
(async () => {
const modules = await wasm()
console.time("sleep_millis")
await modules.sleep_millis(5000)
console.timeEnd("sleep_millis")
})()
export default wasm
Adjusting the template side
Adjusting rollup.js settings
Finally, adjust the build tool settings.
Since I prepared code for the front-end, change the Cargo.toml call.
import rust from "@wasm-tool/rollup-plugin-rust";
export default {
input: {
- example: "Cargo.toml",
+ example: "./src/main.mjs",
},
output: {
dir: "dist/js",
- format: "iife",
sourcemap: true,
},
plugins: [
rust({
serverPath: "js/",
}),
],
};
Adjusting HTML
To support ES6 in HTML,
set the script tag to call as a module
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
- <script src="js/example.js"></script>
+ <script src="js/example.js" type="module"></script>
</body>
</html>
Build
npm run build
npx http-server dist
Execution
Access via browser, and the following will appear in the console after 5 seconds.

|・∀・| Halt!
If you remove await, it becomes an asynchronous timer.
Is it like JS's Timeout?
------------------- ↓ Epilogue starts here ↓-------------------
What is import * as __wbg_star0 from 'env'?
A mysterious error occurred
There was a warning on the Rollup side
Looking into it, there is a strange string at the beginning of the generated JavaScript file.
It seems wasm-pack wrote it out.
import * as __wbg_star0 from 'env';
🤔 Hmm
I looked into it further, and it seems you just need to add the following package.
[dependencies]
・・・
parking_lot = { version = "0.11.1", features = ["wasm-bindgen"]}
Somehow it worked.
Reference:
Discussion