WebAssembly模块可以抛出异常,以便解锁事件循环,以便可以通过其他同步代码来处理事件.目前我能找到的唯一这样的例子是Rust's winit crate.请注意,throw
的实现方式如下:
pub fn throw(msg: &str) {
wasm_bindgen::throw_str(msg);
}
我预计抛出这样的异常将展开WebAssembly堆栈.此外,即使堆栈没有展开,一旦处理了事件(如果有),如何才能重新展开堆栈呢?
WebAssembly模块可以抛出异常,以便解锁事件循环,以便可以通过其他同步代码来处理事件.目前我能找到的唯一这样的例子是Rust's winit crate.请注意,throw
的实现方式如下:
pub fn throw(msg: &str) {
wasm_bindgen::throw_str(msg);
}
我预计抛出这样的异常将展开WebAssembly堆栈.此外,即使堆栈没有展开,一旦处理了事件(如果有),如何才能重新展开堆栈呢?
抛出一个WASM异常并不是"让步".它不会"倒带堆栈".它更类似于panic
-它将终止当前的执行,直到某个东西(通常是浏览器)捕捉到它.没有任何工具可以在代码引发时恢复执行代码.
现在,浏览器可以通过执行其他处理程序和事件再次调用您的代码,但您抛出的点上的堆栈已经消失-类似于在捕捉到catch_unwind
死机后恢复执行.
对于为什么Winit的run
函数会这样做的特定问题:
EventLoop::run
函数的约定是它启动事件循环并永远运行而不再返回(因此返回类型为!
).对于桌面平台,这是相当简单的,因为EventLoop
类型负责实际设置和运行事件循环.
但在浏览器中,情况要复杂得多.实际的事件循环是由浏览器运行的,而不是由Winit运行的,EventLoop::run
需要将控制权返回给该事件循环,以便它可以"启动",但实际上不会返回到Rust代码.
最简单的方法是抛出一个伪异常.异常将中断WASM代码进入浏览器,然后浏览器将开始执行winit和其他设置的所有事件和回调.