使用 JS `Promise` 和 Rust `Future`
网络上的许多 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_variables)] #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`,其中成功的承诺变为 `Ok`,错误的承诺变为 `Err`。
您还可以使用 `extern "C"` 块直接导入 JS 异步函数,并且承诺将自动转换为未来。目前,返回类型必须是 `JsValue` 或根本没有返回
# #![allow(unused_variables)] #fn main() { #[wasm_bindgen] extern "C" { async fn async_func_1() -> JsValue; async fn async_func_2(); } #}
`async` 可以与 `catch` 属性结合使用来管理来自 JS 承诺的错误
# #![allow(unused_variables)] #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,该函数返回一个承诺。为此,您可以使用 `async` 函数和 `#[wasm_bindgen]`
# #![allow(unused_variables)] #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` 变为成功解析的承诺,`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.*
版本。