Skip to content

Commit

Permalink
enhance(core/event): filter js listeners on rust side only then emit …
Browse files Browse the repository at this point in the history
…filtered ids to be triggered (#9151)

* fix(core/event): filter js listeners on rust side only then emit filtered ids to be triggerd

fix regression introduced in #8930 , and reported in #8930 (comment)

* Update .changes/core-js-unlisten-all-regression.md

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>

* Discard changes to .changes/core-js-unlisten-all-regression.md

* object.defineproperty

* add change file [skip ci]

---------

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>
  • Loading branch information
amrbashir and lucasfernog authored Mar 12, 2024
1 parent d349558 commit 79b8a35
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 48 deletions.
5 changes: 5 additions & 0 deletions .changes/enhance-event-emit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tauri": patch:enhance
---

Improve and optimize event emit calls.
5 changes: 0 additions & 5 deletions .changes/fix-js-unlisten-all-race.md

This file was deleted.

17 changes: 6 additions & 11 deletions core/tauri/src/event/listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,6 @@ impl Listeners {
}
}

pub(crate) fn unlisten_all_js(&self, webview_label: &str) {
let js_listeners = self.inner.as_ref();
let mut js_listeners = js_listeners.js_event_listeners.lock().unwrap();
js_listeners.remove(webview_label);
}

pub(crate) fn has_js_listener<F: Fn(&EventTarget) -> bool>(
&self,
event: &str,
Expand Down Expand Up @@ -287,11 +281,12 @@ impl Listeners {
let js_listeners = self.inner.js_event_listeners.lock().unwrap();
webviews.try_for_each(|webview| {
if let Some(handlers) = js_listeners.get(webview.label()).and_then(|s| s.get(event)) {
let handlers = handlers.iter();
let handlers = handlers.filter(|handler| match_any_or_filter(&handler.target, &filter));
for JsHandler { target, .. } in handlers {
webview.emit_js(emit_args, target)?;
}
let ids = handlers
.iter()
.filter(|handler| match_any_or_filter(&handler.target, &filter))
.map(|handler| handler.id)
.collect::<Vec<_>>();
webview.emit_js(emit_args, &ids)?;
}

Ok(())
Expand Down
35 changes: 14 additions & 21 deletions core/tauri/src/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,21 +174,19 @@ pub fn listen_js_script(
handler: &str,
) -> String {
format!(
"
(function () {{
"(function () {{
if (window['{listeners}'] === void 0) {{
Object.defineProperty(window, '{listeners}', {{ value: Object.create(null) }});
}}
if (window['{listeners}']['{event}'] === void 0) {{
Object.defineProperty(window['{listeners}'], '{event}', {{ value: [] }});
Object.defineProperty(window['{listeners}'], '{event}', {{ value: Object.create(null) }});
}}
const eventListeners = window['{listeners}']['{event}']
const listener = {{
id: {event_id},
target: {target},
handler: {handler}
}};
eventListeners.push(listener);
Object.defineProperty(eventListeners, '{event_id}', {{ value: listener, configurable: true }});
}})()
",
listeners = listeners_object_name,
Expand All @@ -199,14 +197,14 @@ pub fn listen_js_script(
pub fn emit_js_script(
event_emit_function_name: &str,
emit_args: &EmitArgs,
serialized_target: &str,
serialized_ids: &str,
) -> crate::Result<String> {
Ok(format!(
"(function () {{ const fn = window['{}']; fn && fn({{event: {}, payload: {}}}, {target}) }})()",
"(function () {{ const fn = window['{}']; fn && fn({{event: {}, payload: {}}}, {ids}) }})()",
event_emit_function_name,
emit_args.event,
emit_args.payload,
target = serialized_target,
ids = serialized_ids,
))
}

Expand All @@ -216,14 +214,10 @@ pub fn unlisten_js_script(
event_id: EventId,
) -> String {
format!(
"
(function () {{
"(function () {{
const listeners = (window['{listeners_object_name}'] || {{}})['{event_name}']
if (listeners) {{
const index = window['{listeners_object_name}']['{event_name}'].findIndex(e => e.id === {event_id})
if (index > -1) {{
window['{listeners_object_name}']['{event_name}'].splice(index, 1)
}}
delete window['{listeners_object_name}']['{event_name}'][{event_id}];
}}
}})()
",
Expand All @@ -232,14 +226,13 @@ pub fn unlisten_js_script(

pub fn event_initialization_script(function: &str, listeners: &str) -> String {
format!(
"
Object.defineProperty(window, '{function}', {{
value: function (eventData, target) {{
"Object.defineProperty(window, '{function}', {{
value: function (eventData, ids) {{
const listeners = (window['{listeners}'] && window['{listeners}'][eventData.event]) || []
for (let i = listeners.length - 1; i >= 0; i--) {{
const listener = listeners[i]
if (listener.target.kind === 'Any' || (listener.target.kind === target.kind && listener.target.label === target.label)) {{
eventData.id = listener.id
for (const id of ids) {{
const listener = listeners[id]
if (listener) {{
eventData.id = id
listener.handler(eventData)
}}
}}
Expand Down
13 changes: 2 additions & 11 deletions core/tauri/src/webview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,9 +571,6 @@ tauri::Builder::default()
.on_page_load_handler
.replace(Box::new(move |url, event| {
if let Some(w) = manager_.get_webview(&label_) {
if let PageLoadEvent::Started = event {
w.unlisten_all_js();
}
if let Some(handler) = self.on_page_load_handler.as_ref() {
handler(w, PageLoadPayload { url: &url, event });
}
Expand Down Expand Up @@ -1302,17 +1299,11 @@ fn main() {
Ok(())
}

/// Unregister all JS event listeners.
pub(crate) fn unlisten_all_js(&self) {
let listeners = self.manager().listeners();
listeners.unlisten_all_js(self.label());
}

pub(crate) fn emit_js(&self, emit_args: &EmitArgs, target: &EventTarget) -> crate::Result<()> {
pub(crate) fn emit_js(&self, emit_args: &EmitArgs, ids: &[u32]) -> crate::Result<()> {
self.eval(&crate::event::emit_js_script(
self.manager().listeners().function_name(),
emit_args,
&serde_json::to_string(target)?,
&serde_json::to_string(ids)?,
)?)?;
Ok(())
}
Expand Down

0 comments on commit 79b8a35

Please sign in to comment.