Преглед на файлове

enhance(core/event): filter js listeners on rust side only then emit 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 https://github.com/tauri-apps/tauri/pull/8930 , and reported in https://github.com/tauri-apps/tauri/pull/8930#issuecomment-1986279046

* 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>
Amr Bashir преди 1 година
родител
ревизия
79b8a3514b
променени са 5 файла, в които са добавени 27 реда и са изтрити 48 реда
  1. 5 0
      .changes/enhance-event-emit.md
  2. 0 5
      .changes/fix-js-unlisten-all-race.md
  3. 6 11
      core/tauri/src/event/listener.rs
  4. 14 21
      core/tauri/src/event/mod.rs
  5. 2 11
      core/tauri/src/webview/mod.rs

+ 5 - 0
.changes/enhance-event-emit.md

@@ -0,0 +1,5 @@
+---
+"tauri": patch:enhance
+---
+
+Improve and optimize event emit calls.

+ 0 - 5
.changes/fix-js-unlisten-all-race.md

@@ -1,5 +0,0 @@
----
-"tauri": patch:bug
----
-
-Fix old JS listeners being dropped on page load after it was possible to create new listeners.

+ 6 - 11
core/tauri/src/event/listener.rs

@@ -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,
@@ -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(())

+ 14 - 21
core/tauri/src/event/mod.rs

@@ -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,
@@ -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,
   ))
 }
 
@@ -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}];
         }}
       }})()
     ",
@@ -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)
           }}
         }}

+ 2 - 11
core/tauri/src/webview/mod.rs

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