SVGHMI: use requestAnimationFrame to delegate rendering of updates from network. Should help prevent browser collapse leading to watchdog in case of overload. svghmi
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Fri, 06 Mar 2020 09:35:08 +0100
branchsvghmi
changeset 2859 517583e21bfd
parent 2858 39c8d6079f0f
child 2860 b7650c6abeda
SVGHMI: use requestAnimationFrame to delegate rendering of updates from network. Should help prevent browser collapse leading to watchdog in case of overload.
svghmi/gen_index_xhtml.xslt
svghmi/svghmi.js
--- a/svghmi/gen_index_xhtml.xslt	Thu Mar 05 13:54:29 2020 +0100
+++ b/svghmi/gen_index_xhtml.xslt	Fri Mar 06 09:35:08 2020 +0100
@@ -623,6 +623,8 @@
 </xsl:text>
     <xsl:text>var cache = hmitree_types.map(_ignored =&gt; undefined);
 </xsl:text>
+    <xsl:text>var updates = {};
+</xsl:text>
     <xsl:text>
 </xsl:text>
     <xsl:text>function dispatch_value_to_widget(widget, index, value, oldval) {
@@ -749,7 +751,33 @@
 </xsl:text>
     <xsl:text>
 </xsl:text>
-    <xsl:text>// Register message reception handler
+    <xsl:text>// Apply updates recieved through ws.onmessage to subscribed widgets
+</xsl:text>
+    <xsl:text>// Called on requestAnimationFram, modifies DOM
+</xsl:text>
+    <xsl:text>function apply_pending_updates() {
+</xsl:text>
+    <xsl:text>    for(let index in updates){
+</xsl:text>
+    <xsl:text>        // serving as a key, index becomes a string
+</xsl:text>
+    <xsl:text>        // -&gt; pass Number(index) instead
+</xsl:text>
+    <xsl:text>        dispatch_value(Number(index), updates[index]);
+</xsl:text>
+    <xsl:text>        delete updates[index];
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>}
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>// Message reception handler
+</xsl:text>
+    <xsl:text>// Hash is verified and HMI values updates resulting from binary parsing
+</xsl:text>
+    <xsl:text>// are stored until browser can compute next frame, DOM is left untouched
 </xsl:text>
     <xsl:text>ws.onmessage = function (evt) {
 </xsl:text>
@@ -791,18 +819,22 @@
 </xsl:text>
     <xsl:text>                let [value, bytesize] = dvgetter(dv,i);
 </xsl:text>
-    <xsl:text>                dispatch_value(index, value);
+    <xsl:text>                updates[index] = value;
 </xsl:text>
     <xsl:text>                i += bytesize;
 </xsl:text>
     <xsl:text>            } else {
 </xsl:text>
-    <xsl:text>                throw new Error("Unknown index "+index)
+    <xsl:text>                throw new Error("Unknown index "+index);
 </xsl:text>
     <xsl:text>            }
 </xsl:text>
     <xsl:text>        };
 </xsl:text>
+    <xsl:text>        // register for rendering on next frame, since there are updates
+</xsl:text>
+    <xsl:text>        window.requestAnimationFrame(apply_pending_updates);
+</xsl:text>
     <xsl:text>    } catch(err) {
 </xsl:text>
     <xsl:text>        // 1003 is for "Unsupported Data"
--- a/svghmi/svghmi.js	Thu Mar 05 13:54:29 2020 +0100
+++ b/svghmi/svghmi.js	Fri Mar 06 09:35:08 2020 +0100
@@ -1,6 +1,7 @@
 // svghmi.js
 
 var cache = hmitree_types.map(_ignored => undefined);
+var updates = {};
 
 function dispatch_value_to_widget(widget, index, value, oldval) {
     try {
@@ -64,7 +65,20 @@
     }
 };
 
-// Register message reception handler
+// Apply updates recieved through ws.onmessage to subscribed widgets
+// Called on requestAnimationFrame, modifies DOM
+function apply_pending_updates() {
+    for(let index in updates){
+        // serving as a key, index becomes a string
+        // -> pass Number(index) instead
+        dispatch_value(Number(index), updates[index]);
+        delete updates[index];
+    }
+}
+
+// Message reception handler
+// Hash is verified and HMI values updates resulting from binary parsing
+// are stored until browser can compute next frame, DOM is left untouched
 ws.onmessage = function (evt) {
 
     let data = evt.data;
@@ -85,12 +99,14 @@
             if(iectype != undefined){
                 let dvgetter = dvgetters[iectype];
                 let [value, bytesize] = dvgetter(dv,i);
-                dispatch_value(index, value);
+                updates[index] = value;
                 i += bytesize;
             } else {
-                throw new Error("Unknown index "+index)
+                throw new Error("Unknown index "+index);
             }
         };
+        // register for rendering on next frame, since there are updates
+        window.requestAnimationFrame(apply_pending_updates);
     } catch(err) {
         // 1003 is for "Unsupported Data"
         // ws.close(1003, err.message);