使用 JS `Promise` 和 Rust `Future`
Web 上的许多 API 都使用 `Promise`,例如 JS 中的 `async` 函数。自然地,您可能希望从 Rust 中与它们进行交互!为此,您可以使用 `wasm-bindgen-futures` crate 以及 Rust `async` 函数。
您可能会遇到的第一个问题是需要使用 `Promise`。为此,您需要使用 js_sys::Promise
。获得其中一个值后,您可以将该值转换为 wasm_bindgen_futures::JsFuture
。此类型实现了 `std::future::Future` 特性,允许您在 `async` 函数中自然地使用它。例如
#![allow(unused)] fn main() { async fn get_from_js() -> Result<JsValue, JsValue> { let promise = js_sys::Promise::resolve(&42.into()); let result = wasm_bindgen_futures::JsFuture::from(promise).await?; Ok(result) } }
在这里,我们可以看到如何将 `Promise` 转换为 Rust 创建一个 impl Future<Output = Result<JsValue, JsValue>>
。这对应于 JS 中的 `then` 和 `catch`,其中成功的 promise 变成 `Ok`,错误的 promise 变成 `Err`。
您还可以使用 `extern "C"` 块直接导入 JS 异步函数,并且 promise 将自动转换为 future。目前,返回值必须是 `JsValue` 或根本没有返回值
#![allow(unused)] fn main() { #[wasm_bindgen] extern "C" { async fn async_func_1() -> JsValue; async fn async_func_2(); } }
`async` 可以与 `catch` 属性结合使用来管理来自 JS promise 的错误
#![allow(unused)] fn main() { #[wasm_bindgen] extern "C" { #[wasm_bindgen(catch)] async fn async_func_3() -> Result<JsValue, JsValue>; #[wasm_bindgen(catch)] async fn async_func_4() -> Result<(), JsValue>; } }
接下来,您可能希望将 Rust 函数导出到 JS,该函数返回一个 promise。为此,您可以使用 `async` 函数和 `#[wasm_bindgen]`
#![allow(unused)] fn main() { #[wasm_bindgen] pub async fn foo() { // ... } }
从 JS 调用时,这里的 `foo` 函数将返回一个 `Promise`,因此您可以将其导入为
import { foo } from "my-module";
async function shim() {
const result = await foo();
// ...
}
`async fn` 的返回值
在 Rust 中使用 `async fn` 并将其导出到 JS 时,对返回值有一些限制。导出的 Rust 函数的返回值最终将变成 `Result<JsValue, JsValue>`,其中 `Ok` 变成成功解析的 promise,`Err` 等同于抛出异常。
以下类型支持作为 `async fn` 的返回值
()
- 转换为 JS 中成功的 `undefined`T: Into<JsValue>
- 转换为成功的 JS 值Result<(), E: Into<JsValue>>
- 如果Ok(())
转换为成功的 `undefined`,否则转换为失败的 promise,并将 `E` 转换为 JS 值Result<T: Into<JsValue>, E: Into<JsValue>>
- 与上一个情况类似,只是两个数据有效载荷都被转换为 `JsValue`。
请注意,许多类型都实现了转换为 `JsValue`,例如所有通过 `#[wasm_bindgen]` 导入的类型(即 `js-sys` 或 `web-sys` 中的类型)、`u32` 等基本类型以及所有导出的 `#[wasm_bindgen]` 类型。一般来说,您应该能够编写代码而无需进行太多显式转换,宏应该会处理其余部分!
使用 `wasm-bindgen-futures`
`wasm-bindgen-futures` crate 弥合了 JavaScript `Promise` 和 Rust `Future` 之间的差距。它的 `JsFuture` 类型提供了从 JavaScript `Promise` 转换为 Rust `Future` 的转换,它的 `future_to_promise` 函数将 Rust `Future` 转换为 JavaScript `Promise` 并安排它被驱动到完成。
了解更多
与 `Future` 版本的兼容性
crates.io 上的当前 crate,`wasm-bindgen-futures 0.4.*`,支持 Rust 中的 `std::future::Future` 和 `async`/`await`。这通常需要 Rust 1.39.0+(截至 2019-09-05 在撰写本文时,它是 Rust 的 nightly 通道)。
如果您使用的是 `futures` `0.1.*` crate 中的 `Future` 特性,那么您需要使用 crates.io 上的 `wasm-bindgen-futures` 的 `0.3.*` 轨道。