使用 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
trait,这使得它可以自然地在 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
,其中成功的 promise 变为 Ok
,而错误的 promise 变为 Err
。
你还可以直接使用 extern "C"
块导入 JS 异步函数,并且 promise 会自动转换为 future。目前,返回类型必须是 JsValue
或不返回任何值
# #![allow(unused_variables)] #fn main() { #[wasm_bindgen] extern "C" { async fn async_func_1_ret_number() -> JsValue; async fn async_func_2(); } async fn get_from_js() -> f64 { async_func_1_ret_number().await.as_f64().unwrap_or(0.0) } #}
可以将 async
与 catch
属性结合使用来管理来自 JS promise 的错误
# #![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>; } #}
接下来,你可能希望导出一个返回 promise 的 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
转换为成功解析的 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
trait,那么你将需要使用 crates.io 上 wasm-bindgen-futures
的 0.3.*
track。