Prechádzať zdrojové kódy

#338 introduce update queue

Falko Schindler 2 rokov pred
rodič
commit
9db6daacc8
3 zmenil súbory, kde vykonal 44 pridanie a 9 odobranie
  1. 3 8
      nicegui/element.py
  2. 2 1
      nicegui/nicegui.py
  3. 39 0
      nicegui/updates.py

+ 3 - 8
nicegui/element.py

@@ -5,10 +5,9 @@ from abc import ABC
 from copy import deepcopy
 from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Union
 
-from . import background_tasks, binding, globals
+from . import background_tasks, binding, events, globals, updates
 from .elements.mixins.visibility import Visibility
 from .event_listener import EventListener
-from .events import handle_event
 from .slot import Slot
 
 if TYPE_CHECKING:
@@ -159,7 +158,7 @@ class Element(ABC, Visibility):
     def handle_event(self, msg: Dict) -> None:
         for listener in self._event_listeners:
             if listener.type == msg['type']:
-                handle_event(listener.handler, msg, sender=self)
+                events.handle_event(listener.handler, msg, sender=self)
 
     def collect_descendant_ids(self) -> List[int]:
         '''includes own ID as first element'''
@@ -170,11 +169,7 @@ class Element(ABC, Visibility):
         return ids
 
     def update(self) -> None:
-        if not globals.loop:
-            return
-        ids = self.collect_descendant_ids()
-        elements = {id: self.client.elements[id].to_dict() for id in ids}
-        background_tasks.create(globals.sio.emit('update', {'elements': elements}, room=self.client.id))
+        updates.enqueue(self)
 
     def run_method(self, name: str, *args: Any) -> None:
         if not globals.loop:

+ 2 - 1
nicegui/nicegui.py

@@ -10,7 +10,7 @@ from fastapi.responses import FileResponse, Response
 from fastapi.staticfiles import StaticFiles
 from fastapi_socketio import SocketManager
 
-from . import background_tasks, binding, globals
+from . import background_tasks, binding, globals, updates
 from .app import App
 from .client import Client
 from .dependencies import js_components, js_dependencies
@@ -61,6 +61,7 @@ def handle_startup(with_welcome_message: bool = True) -> None:
         for t in globals.startup_handlers:
             safe_invoke(t)
     background_tasks.create(binding.loop())
+    background_tasks.create(updates.loop())
     background_tasks.create(prune_clients())
     background_tasks.create(prune_slot_stacks())
     globals.state = globals.State.STARTED

+ 39 - 0
nicegui/updates.py

@@ -0,0 +1,39 @@
+import asyncio
+from typing import TYPE_CHECKING, Dict, List, Set
+
+from . import globals
+
+if TYPE_CHECKING:
+    from .element import Element
+
+update_queue: Dict[int, List] = {}  # element id -> [element, attributes]
+
+
+def enqueue(element: 'Element', *attributes: str) -> None:
+    '''Schedules a UI update for this element.
+
+    Attributes can be 'class', 'style', 'props', or 'text'.
+    '''
+    if element.id not in update_queue:
+        update_queue[element.id] = [element, list(attributes)]
+    else:
+        queued_attributes: Set[str] = update_queue[element.id][1]
+        if queued_attributes and attributes:
+            queued_attributes.update(attributes)
+        else:
+            queued_attributes.clear()
+
+
+async def loop() -> None:
+    '''Repeatedly updates all elements in the update queue.'''
+    while True:
+        elements: Dict[int, 'Element'] = {}
+        for _, value in update_queue.items():
+            element: 'Element' = value[0]
+            for id in element.collect_descendant_ids():
+                elements[id] = element.client.elements[id].to_dict()
+        if elements:
+            await globals.sio.emit('update', {'elements': elements}, room=element.client.id)
+            update_queue.clear()
+        else:
+            await asyncio.sleep(0.01)