使用 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_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)] 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.*
版本。