Was ist ein besserer Weg, um mit Schließungen in WebAssembly mit Rust umzugehen, anstatt zu vergessen und Speicher zu verlieren?

8

Wie kann man beim Bereitstellen von Rückrufen für JavaScript mithilfe von Closures besser damit umgehen, dass sie nicht freigegeben werden? Der wasm-bindgen-Leitfaden schlägt die Verwendung vor .forget, gibt jedoch zu, dass dies im Wesentlichen zu einem Speicherverlust führt.

Normalerweise speichern wir das Handle, damit es später zu einem geeigneten Zeitpunkt gelöscht wird. Derzeit möchten wir jedoch, dass es sich um einen globalen Handler handelt. Daher verwenden wir die forgetMethode, um es zu löschen, ohne den Abschluss ungültig zu machen. Beachten Sie, dass dadurch Speicher in Rust verloren geht, daher sollte dies mit Bedacht erfolgen!

Es weist darauf hin, den Verschluss bis zu einem Zeitpunkt aufzubewahren, an dem es angebracht ist, ihn fallen zu lassen. In Alexcrichtons Antwort auf eine frühere Frage erwähnt er ...

[...] wenn es [...] nur einmal aufgerufen wird, können Sie Rc/ verwenden RefCell, um das ClosureInnere des Verschlusses selbst fallen zu lassen (unter Verwendung einiger innerer Mutabilitäts-Spielereien)

Ein Beispiel für diese Methode liefert er jedoch nicht.

Die Closure-Dokumentation enthält auch ein Beispiel für die Rückgabe des Verweises auf den Closure an den JavaScript-Kontext, damit dieser festlegen kann, wann der Verweis freigegeben werden soll.

Wenn wir hier fallen cbwürden, würde eine Ausnahme ausgelöst, wenn das Intervall abgelaufen ist. Stattdessen wir zurückkehren unseren Griff zurück in JS so kann JS entscheiden , wann das Intervall abzubrechen und den Verschluss freizugeben.

Ich würde mir auch vorstellen, dass es Möglichkeiten gibt, Funktionen wie Lebensdauern oder das #[wasm_bindgen]Makro für eine öffentliche Funktion zu verwenden, um dieses Problem zu vermeiden, aber ich habe Probleme, herauszufinden, wie es so gemacht wird.

Meine Frage ist, welche Alternativen zur Verwendung .forgetmit Verschlüssen bestehen, die von Rust an JavaScript zurückgegeben werden. Kann ich bitte einige einfache Beispiele für jede verwendete Option sehen?

dynamitereed
quelle

Antworten:

1

Ich habe kürzlich eine kleine kommerzielle App erstellt und war wochenlang damit beschäftigt und war sehr aufgeregt, als ich diese zum Laufen brachte. Am Ende habe ich Closure.once_into_js verwendet . Dies hat jedoch auch die Einschränkung, dass "die Freigabe des FnOnce nur durch Aufrufen der JavaScript-Funktion aufgehoben wird. Wenn die JavaScript-Funktion niemals aufgerufen wird, leckt das FnOnce und alles, worüber es schließt." Wenn also der Rückruf aufgerufen wird, sollte alles in Ordnung sein, aber wenn nicht, liegt immer noch ein Speicherverlust vor. Ich fand den Programmierstil ziemlich nett. Ich habe die JavaScript-Funktionen wie folgt auf Rust abgebildet:

#[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())   
    ));
}

Und dann kann ich es von Rust in meiner App so verwenden:

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

Ich habe die Rückrufe als statische Impl-Funktionen definiert und dann die Werte verschoben.

Cameron Taggart
quelle