首页 > 解决方案 > 用 Rust 处理 WebAssembly 中的闭包而不是使用忘记和泄漏内存有什么更好的方法?

问题描述

当使用Closures向 JavaScript 提供回调时,有什么更好的方法来避免释放它们?wasm -bindgen 指南建议使用.forget,但承认这本质上是内存泄漏。

通常我们会存储句柄以便稍后在适当的时间删除,但现在我们希望它是一个全局处理程序,所以我们使用该forget方法删除它而不会使闭包无效。请注意,这会在 Rust 中泄漏内存,因此应该明智地执行此操作!

它暗示将闭包存储到适合丢弃的时间。在alexcrichton 对一个问题的回答中,他提到...

[...] 如果它 [...] 只被调用一次,那么您可以使用Rc/RefCellClosure闭包本身放入内部(使用一些内部可变性恶作剧)

但他没有提供这种方法的例子。

Closure 文档还提供了一个将闭包的引用返回给 JavaScript 上下文以让它处理何时释放引用的示例。

如果我们要放弃cb这里,它将导致每当间隔过去时引发异常。相反,我们将句柄返回给 JS,以便 JS 决定何时取消间隔并释放闭包。

我还想象有一些方法可以#[wasm_bindgen]在公共函数上使用生命周期或宏等功能来避免这个问题,但我很难弄清楚如何做到这一点。

我的问题是,使用.forget从 Rust 传回 JavaScript 的闭包有哪些替代方法,我可以看看使用中每个选项的一些简单示例吗?

标签: rustclosureswebassemblywasm-bindgen

解决方案


我最近构建了一个小型商业应用程序,并且在这个应用程序上卡了几个星期,当我开始工作时真的很兴奋。我最终使用了Closure.once_into_js。然而,这也有一个警告,“释放 FnOnce 的唯一方法是调用 JavaScript 函数。如果 JavaScript 函数从未被调用,那么 FnOnce 及其关闭的所有内容都会泄漏。” 所以如果回调被调用,一切都应该没问题,但如果没有,仍然存在内存泄漏。我发现编程风格非常好。我将 JavaScript 函数映射到 Rust,如下所示:

#[wasm_bindgen]
fn getSomething(details: &JsValue, callback: JsValue);

pub fn get_something(details: &Details, callback: impl Fn(Option<String>) + 'static){
    getSomething(&serde_wasm_bindgen::to_value(details).unwrap(), Closure::once_into_js(move |v: JsValue| 
        callback(serde_wasm_bindgen::from_value(v).unwrap())   
    ));
}

然后我可以在我的应用程序中从 Rust 使用它,如下所示:

let callback = move |id| {
};
get_something(&details, callback);

我将回调定义为静态 impl 函数,然后将值移入。


推荐阅读