使用 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
,其中成功的 promise 變成 Ok
,而錯誤的 promise 變成 Err
。
您也可以直接使用 extern "C"
區塊匯入 JS async 函式,並且 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>; } #}
接下來,您可能想要將一個 Rust 函式匯出到 JS,該函式會回傳一個 promise。為此,您可以使用 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
特徵,則您會想使用 crates.io 上 wasm-bindgen-futures
的 0.3.*
版本。