Performance Optimizations + Minor Bugfix#93
Open
Jakob-Gliwa wants to merge 6 commits into
Open
Conversation
added 6 commits
January 1, 2026 19:28
- Add _stateIndex Map in prepareStructure() for O(1) lookups - Replace O(n) linear search in findControlByState() with Map lookup - Support both string UUIDs and array UUIDs (multi-value states) - Two-pass approach: build controls first, then index (parent priority) - Reduces lookup time from 31.6µs to <0.01µs per event
- Add _keepaliveNodes array in constructor for direct node management - Replace RED.nodes.eachNode() in keepalive handler with direct array iteration - Replace RED.nodes.eachNode() in sendOnlineNodeMsg() with direct array iteration - Add registerKeepaliveNode() and deregisterKeepaliveNode() methods - Update LoxoneKeepaliveNode to register/deregister on create/close - Reduces iteration from O(n) all nodes to O(k) relevant nodes only
- Replace buggy forEach+splice pattern with indexOf+splice in all deregister methods - Fix deregisterOnlineNode(), deregisterInputNode(), deregisterOutputNode() - Fix deregisterStreamInNode(), deregisterStreamAllNode(), deregisterWebserviceNode() - Fix removeWebserviceNodeFromQueue() using findIndex for handler+uri matching - Prevents skipping elements when array is modified during iteration - Improves performance by eliminating callback overhead and using native indexOf - deregisterKeepaliveNode() already fixed in Opt codmpm#3
- Add _parseEventValue() helper function with type-check first
- Avoid expensive try/catch exceptions on Numbers/Objects (node-lox-ws-api returns native types)
- Use Set for fast JSON start character lookup
- Replace try/catch JSON.parse in buildMsgObject() with optimized parser
- Prevents exception overhead: Numbers/Objects returned directly without parsing
- Only parse strings that start with { or [ (potential JSON)
- Mixed workload: 81x faster (80% Numbers, 15% Strings, 5% Objects)
- Numbers: 10x faster, Strings: 144x faster, Objects: 886-913x faster
…rs to module scope Optimization codmpm#9: Denormalized Index (+6% speedup) - Pre-resolve room/category names in state index during structure load - Avoids 2x Object lookup per event at runtime - Extend state index entries with roomName and categoryName fields Optimization codmpm#10: Message Template Cache (+7% speedup) - Pre-build message templates with all static fields - Only payload changes per event (template clone + payload update) - Reduces object creation overhead significantly Code improvements: - Compact buildMsgObject() implementation (22 lines saved, 54% reduction) - Use spread operator for template cloning - Use optional chaining and nullish coalescing for cleaner code - Move helper functions to module scope (not recreated per instance) - limitString: arrow function with template literals - parseEventValue: module-level function - JSON_START: module-level constant - Fix _parseEventValue scope issue (was causing ReferenceError) Total expected speedup: +13% (from Opt codmpm#9 + codmpm#10)
- Change node-lox-ws-api dependency from codm/node-lox-ws-api to Jakob-Gliwa/node-lox-ws-api - Bump version to 0.10.13.1 for testing new lox-ws-api fork
Owner
|
Hey Jakob. Could you also do a pull request for https://github.com/codm/node-lox-ws-api/ with your changes made to the underlying API. Cheers, |
Contributor
Author
|
Hey Patrik, all changes except 1e81ab3 will work without changes to the lox-ws-api. Is it possible to just accept the other commits and ignore the changes to package.json? I just added it to test out some perf-relevant changes to the lox-ws-api - mainly I ported it to the native ws lib from websocket, which worked quite well. I you are interested in that change I could also open a pull request for that. Best, |
Owner
|
Would be great to also get the changes for lox-ws-api 👍🏻 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hi there - thank you for your node-red Loxone Plugin.
Been using it for years!
I was recently wondering why my node-red docker was so busy (10-15% CPU on an Intel N100) and traced it back to this plugin.
Major Improvement:
Core issue is/was that the current version iterates over all controls on every event.
Due to many energy-meters I have tons of events, so this operation was pretty costly.
I refactored it to a map.
For me this reduced the CPU pressure from 10-15% to about 0,5-2%.
=> If you just accept minor changes, this would be the most important one
Minor Improvements
Whilst on it I also added a couple of other performance improvements (caching the structured states, holding nodes directly accessible instead of iterations through all nodes, bit optimized Value Event parsing, etc.)
Bugfix
Also I fixed a bug in the deregistering of nodes (removals within loop).
Disclaimer:
I'm not super proficient in JS so I used AI (mainly Opus 4.5, GPT 5.2 Pro) to a) find the issues, b) Benchmark & Test the Optimizations and c) fix the issues.