预期的 `()`,发现异步函数的不透明类型
expected `()`, found opaque type for async function
我在主范围内关注 a guide for setting up a WebRTC data-channel with web-sys. I can copy and paste the code and it compiles correctly. The start() function is async which makes it possible to await a JsFuture,但是我试图将此 await 移动到 onmessage_callback
块。只需将这一行添加到原始实现中,我就有了:
let onmessage_callback =
Closure::wrap(
Box::new(move |ev: MessageEvent| {
let desc = JsFuture::from(pc1.create_offer()).await.unwrap();
match ev.data().as_string() {
Some(message) => {
console_warn!("{:?}", message);
dc1_clone.send_with_str("Pong from pc1.dc!").unwrap();
}
None => {}
}
}) as Box<dyn FnMut(MessageEvent)>,
);
dc1.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
onmessage_callback.forget();
一旦我编译它,我当然会收到一条错误消息,指出等待未来 desc
只能在异步上下文中进行。我想我可以在定义 FnMut
函数时添加 async
关键字:
let onmessage_callback =
Closure::wrap(
Box::new(move |ev: MessageEvent| async { // <-- async
let desc = JsFuture::from(pc1.create_offer()).await.unwrap();
match ev.data().as_string() {
Some(message) => {
console_warn!("{:?}", message);
dc1_clone.send_with_str("Pong from pc1.dc!").unwrap();
}
None => {}
}
}) as Box<dyn FnMut(MessageEvent)>,
);
dc1.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
onmessage_callback.forget();
但是当我编译这个时,我得到以下错误:
error[E0271]: type mismatch resolving `<[closure@src/lib.rs:48:22: 57:14] as FnOnce<(MessageEvent,)>>::Output == ()`
--> src/lib.rs:48:13
|
48 | / Box::new(move |ev: MessageEvent| async {
49 | | let desc = JsFuture::from(pc1.create_offer()).await.unwrap();
50 | | match ev.data().as_string() {
51 | | Some(message) => {
... |
56 | | }
57 | | }) as Box<dyn FnMut(MessageEvent)>,
| |______________^ expected `()`, found opaque type
|
= note: expected unit type `()`
found opaque type `impl Future<Output = [async output]>`
= note: required for the cast to the object type `dyn FnMut(MessageEvent)`
我不确定如何进行此操作,我认为错误是说回调 returns 一个未来,但它应该是无效的。
如何定义异步回调?
你通过说
声明你的函数不会return任何东西
Box<dyn FnMut(MessageEvent)>
//which is the same thing as Box<dyn FnMut(MessageEvent)->()>
然后在你的回调中,你实际上 return 返回一个异步块。
我不熟悉相关库,但查看文档时您不应该传递异步函数。
如果您必须使用异步并且如果您已经有运行时运行,您可以在同步块中生成一个任务。
但在 javascript 世界中,如果某些东西是异步的,你不能真正等待它,你只能给它一个回调(async/await 关键字存在,但它们所做的只是 return 你另一个承诺)
所以我相信你应该在这里使用 promise API 并为 then
方法提供回调。
这不是很漂亮,但这就是 js 世界中事情的完成方式,你在这里面对的是 js 中的 callback hell,这是一个东西 :D
Ps:
Javascript 有一个单线程运行时,事情被安排在一个永远的 运行 循环上,称为事件循环。每次你在某处传递回调时,它都会在事件循环中注册并最终被调用。
重要的是要理解它的调用部分是无法保证的,如果您要在一个回调中阻止事件循环,那么循环的下一个滴答将永远不会到来,因此整个运行时将被锁定。这就是导致回调地狱的设计决策背后的原因
Pps:
我真的不认为你应该将 rust 异步运行时与你的 wasm 二进制文件捆绑在一起(如果可能的话),因为正如我提到的那样,js 有它自己的,只是坚持承诺 api
原因如@nikoss 所述,您传递了一个 future-returning 函数并将其转换为 unit-returning 函数。
至于如何解决这个问题,您可以使用 spawn_local()
:
在 JS promise 微任务队列上生成未来
let (pc1_clone, dc1_clone) = (pc1.clone(), dc1.clone());
let onmessage_callback =
Closure::wrap(
Box::new(move |ev: MessageEvent| {
wasm_bindgen_futures::spawn_local(async move {
let desc = JsFuture::from(pc1_clone.create_offer()).await.unwrap();
match ev.data().as_string() {
Some(message) => {
console_warn!("{:?}", message);
dc1_clone.send_with_str("Pong from pc1.dc!").unwrap();
}
None => {}
}
});
}) as Box<dyn FnMut(MessageEvent)>,
);
dc1.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
onmessage_callback.forget();
我在主范围内关注 a guide for setting up a WebRTC data-channel with web-sys. I can copy and paste the code and it compiles correctly. The start() function is async which makes it possible to await a JsFuture,但是我试图将此 await 移动到 onmessage_callback
块。只需将这一行添加到原始实现中,我就有了:
let onmessage_callback =
Closure::wrap(
Box::new(move |ev: MessageEvent| {
let desc = JsFuture::from(pc1.create_offer()).await.unwrap();
match ev.data().as_string() {
Some(message) => {
console_warn!("{:?}", message);
dc1_clone.send_with_str("Pong from pc1.dc!").unwrap();
}
None => {}
}
}) as Box<dyn FnMut(MessageEvent)>,
);
dc1.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
onmessage_callback.forget();
一旦我编译它,我当然会收到一条错误消息,指出等待未来 desc
只能在异步上下文中进行。我想我可以在定义 FnMut
函数时添加 async
关键字:
let onmessage_callback =
Closure::wrap(
Box::new(move |ev: MessageEvent| async { // <-- async
let desc = JsFuture::from(pc1.create_offer()).await.unwrap();
match ev.data().as_string() {
Some(message) => {
console_warn!("{:?}", message);
dc1_clone.send_with_str("Pong from pc1.dc!").unwrap();
}
None => {}
}
}) as Box<dyn FnMut(MessageEvent)>,
);
dc1.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
onmessage_callback.forget();
但是当我编译这个时,我得到以下错误:
error[E0271]: type mismatch resolving `<[closure@src/lib.rs:48:22: 57:14] as FnOnce<(MessageEvent,)>>::Output == ()`
--> src/lib.rs:48:13
|
48 | / Box::new(move |ev: MessageEvent| async {
49 | | let desc = JsFuture::from(pc1.create_offer()).await.unwrap();
50 | | match ev.data().as_string() {
51 | | Some(message) => {
... |
56 | | }
57 | | }) as Box<dyn FnMut(MessageEvent)>,
| |______________^ expected `()`, found opaque type
|
= note: expected unit type `()`
found opaque type `impl Future<Output = [async output]>`
= note: required for the cast to the object type `dyn FnMut(MessageEvent)`
我不确定如何进行此操作,我认为错误是说回调 returns 一个未来,但它应该是无效的。
如何定义异步回调?
你通过说
声明你的函数不会return任何东西Box<dyn FnMut(MessageEvent)>
//which is the same thing as Box<dyn FnMut(MessageEvent)->()>
然后在你的回调中,你实际上 return 返回一个异步块。
我不熟悉相关库,但查看文档时您不应该传递异步函数。
如果您必须使用异步并且如果您已经有运行时运行,您可以在同步块中生成一个任务。
但在 javascript 世界中,如果某些东西是异步的,你不能真正等待它,你只能给它一个回调(async/await 关键字存在,但它们所做的只是 return 你另一个承诺)
所以我相信你应该在这里使用 promise API 并为 then
方法提供回调。
这不是很漂亮,但这就是 js 世界中事情的完成方式,你在这里面对的是 js 中的 callback hell,这是一个东西 :D
Ps: Javascript 有一个单线程运行时,事情被安排在一个永远的 运行 循环上,称为事件循环。每次你在某处传递回调时,它都会在事件循环中注册并最终被调用。
重要的是要理解它的调用部分是无法保证的,如果您要在一个回调中阻止事件循环,那么循环的下一个滴答将永远不会到来,因此整个运行时将被锁定。这就是导致回调地狱的设计决策背后的原因
Pps:
我真的不认为你应该将 rust 异步运行时与你的 wasm 二进制文件捆绑在一起(如果可能的话),因为正如我提到的那样,js 有它自己的,只是坚持承诺 api
原因如@nikoss 所述,您传递了一个 future-returning 函数并将其转换为 unit-returning 函数。
至于如何解决这个问题,您可以使用 spawn_local()
:
let (pc1_clone, dc1_clone) = (pc1.clone(), dc1.clone());
let onmessage_callback =
Closure::wrap(
Box::new(move |ev: MessageEvent| {
wasm_bindgen_futures::spawn_local(async move {
let desc = JsFuture::from(pc1_clone.create_offer()).await.unwrap();
match ev.data().as_string() {
Some(message) => {
console_warn!("{:?}", message);
dc1_clone.send_with_str("Pong from pc1.dc!").unwrap();
}
None => {}
}
});
}) as Box<dyn FnMut(MessageEvent)>,
);
dc1.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
onmessage_callback.forget();