There's a couple problems here. You are using async/await. In character sheets, async/await will not work with the sole exception of using it to await startRoll. Any other usage will break the link between the thread and the active character sheet A minor issue that is easily fixed is that you'd also need to add the Jquery stub listener so that any events triggering that also use this setup. The properties of event usually contain the newValue, but there are a few things that can cause them to not contain the appropriate newValue/previousValue. The big one that I remember here is that API caused changes to attributes don't, but I belive there's a few others as well. It's been so long since I relied on the event properties that I've forgotten all the ways it could get screwed up. This means you have to do a getAttrs anyways regardless of what you are doing. Similarly to problem #2, the API can cause multiple changes at once. This will cause a race condition to occur. Depending on when you set your isFirst variable, you will either wind up with the object containing the character information being out of date (empty if this is the first run) (which is bad), or the initialization will run multiple times. The multiple runs might not seem bad, but if any of those are setting variables, you wind up with each "thread" being desync'd and seeing different data. The global variables are global for the client, so this data has to be indexed by some sort of character sheet unique identifier (like the character ID). However, then you still need to do a getAttrs for every event so that you know which set of data to grab for any given event. Issues #1 and #2 are just code setup issues that are easy to fix. Unfortunately the other issues are more serious. Issue #4 is probably the biggest issue that could cause errors that would be very difficult to track down because they'd manifest differently each time. Issues #3 and #5 mean that you're still having to do a getAttrs with each event anyways, so you aren't actually saving that much time; roughly 0ms per event if the event doesn't need repeating section information, and even if it does require repeating section information you're only saving ~10ms per repeating section you need information from. So you're adding some code complexity for no real performance gains (definitely not gains that a human can notice). The big time sink in sheetworkers is setAttrs which takes ~100ms per call, so the best way to make efficient sheetworkers is to make as few setAttrs calls as possible; e.g. set all the attributes from a given change at once and DON'T do cascading events where you rely on the event detection to propagate a change through all the things that depend on it. To make the long story short, you're on the right track with wanting to reduce the calls to the network, but the way to actually improve performance is to have every event get all attribute data for the sheet and then setup a pseudo event cascade within that thread so that all your changes are combined into a single setAttrs. You wind up with a few tens of milliseconds of extra time for any given event, but the overall performance for complex interactions is several hundred milliseconds faster. This is what the K-scaffold does to ensure that you can write simple sheetworker functions without needing to worry about the event handling. For those interested, a more detailed breakdown of the code efficiency of cascading events vs. single setAttrs is below. Here's an example of this in human readable logic instead of code. The setup for this demonstration is: attribute1, attribute2, and attribute3 are user editable dependent1 = attribute1/attribute2 dependent2 = dependent1 + attribute3 Cascading events method: When attribute1 or attribute2 are changed by the user, dependent1 is set by the sheetworker. The listener sees dependent1 change and fires a new event to calculate and set dependent2. The total time for this pathway is going to be about 10ms for each getAttrs (20ms total) and about 100ms for each setAttrs (200ms total) for a total of ~220ms. Single setAttrs method: When attribute1 or attribute2 is changed by the user, a function is fired which sets dependent1 and calculates dependent2. When attribute3 is changed by the user a function is fired which sets dependent2. The total time for this pathway, regardless of which attribute is edited by the user will be ~10ms for the getAttrs and ~100ms for the setAttrs for a total of 110ms. Now, the difference between these two pathways wouldn't be detectable by a human user, but imagine if you scale this up to a pathway that has 5, 6, 7, or more dependent attributes we can see a huge difference. Using the cascading event method, each of those is going to add ~110ms to the total resolution time. Around ~500ms a user will start to notice the delay, and at ~1 second the delay will be long enough that the user can reliably cause another user caused change while the calculations of the first are still resolving creating a race condition that can cause calculations to be unreliable. With the single setAttrs method, the resolution time for these dependent attributes will always be ~110ms whether you're doing a chain of 2 dependents or 10,000 dependents.