Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

'setTimeout' handler took XXXXms - Why ?

Hi, i'm working on a sheet since at least a year (for Exated 3e), and more and more my players tell me that there is lag in the sheet when they use some features, like the dice roller (rolls on Exalted can be tricky) I've tried to use their character sheet, and yeah, when they or I change a value in most situation, even if no sheetworker script is triggered,  in Chrome console  i get a message saying [Violation] 'setTimeout' handler took 1311ms it appears when roll20 try to refresh the sheet values displayed, but i don't understand why it's so long it correlate with the number of repeatable items i have overall kinda (on a fresh sheet, there is almost no "lag", on more problematic one its 2xxxms PER refresh, sometime twice per player action because of some script) I don't have any setTimeout in my code so ... i assume it come from the roll20 base script/library. As the sheet is "frozen" while this happens, its really problematic and, even by commenting some code (removing sheetworker triggerred usually by this change), i can't find how i can improve this really effectively, or even if i am responsible ^^' If anyone is willing to help a bit, it'll be greatly appreciated
1713287746
GiGs
Pro
Sheet Author
API Scripter
The lag you're describing sounds like it's related to the design of the sheet (probably the sheet workers) and it's hard to say what the problem is without seeing the code. Roll20 has its own internal code we never see that does stuff with the sheet, but it works based on the code we have built. If iyt takes too long to run, you'll see errors. There are certain functions (eg getSttras, setAttrs, amd getSectionIDs) called asynchronous functions. For these to run, they have to contact the roll20 sevrers and wait for a response before doing anything.If you have many such called in a single sheet worker, or in a chain* triggered by a sheet  worker, it can cause significant lag. * For example, setAttrs changes attributes, which might then be modified. For instance, sayin D&D you modify the DEX attribute, that then triggers every other sheet worker that uses change:dex, which includes all skills, the reflex saving through, ranged attacks(which may be jn a repeating section) and possibly more. For every single worker, the Roll20 servers mustbe contacted at least twice (once for the getAttrs and again for the setAttrs) and if the workers are set up sloppily, you might have several such calls in the same sheetworker. Every single the sheet contacts the roll20 severs, there's a time delay as the server must prepare a response and the worker has to wait for it. If you don't take this into account, you can easily end up with too many sheet workers firing. Alternatively if your sheet is very large, and/or has many autocalc fields, you can also get a lag. It's impossible to guess what might be the problem in your case without seeing the sheet code. Does the lag go away if you remove the entire script block for your sheets and save it?
1713290215

Edited 1713290372
You can find my code here :&nbsp; <a href="https://github.com/groch/roll20_exalted_stuff/tree/main" rel="nofollow">https://github.com/groch/roll20_exalted_stuff/tree/main</a> but its a good idea to try that, i commented only the change: on my sheet, i'll try removing all the sheetworker thing Ok so, after the test, there is still the exact same delay without the entire script (removed everything inside the &lt;script&gt;&lt;/script&gt; tag at start of the sheet) on the code, i tried to do my best but ... i know not everything is clean, if you have some advices to give, feel free ! but beware, it's the work of a madman x) I have many autocalc fields, but on the repeatable item i modify (a line of the "dice roller"), there is 7 (well, 6, one is a span showing an attribute like a readonly input) it feels like it try to update ALL fields in all repeatables sections, which then could take an huge chunk of time And yeah i know that there is many calls to the server, but in some cases, the update is not that long so i try to pinpoint in what case Thanks for your time !
1713294381
GiGs
Pro
Sheet Author
API Scripter
I had a quick glance at your sheet workers and I can see fixing this would be a full time job. So I can just give a few tips: It looks like you are using Roll20Async to get async functionality. IIRC, for big sheets, this can be very slow - much, much slower than not using it, because it makes many more getAttrs/setAttrs calls than are needed. My guess would normally be that this is where your lag is coming from - except that your lag is unchanged if you remove the script block. That leaves: There is a LOT of HTML, you might need to look for ways to hide some of it when not in use. (But you may already be doing that, with tabs, etc.). Also, the HTML part of the sheet might be suffering from an attack of divitis (I'm not 100% sure, I didn;'t look closely). All I can really suggest is start the sheet over from scratch, with an eye to keeping to as few visible elements as possible, and replace autocalc fields with sheet workers (they are way, way more efficient). Bear in mind, you can remove HTML just like you did with the sheet block (then put it back later) so can experiment to see if there is a specific part of the sheet causing a lot of lag.
1713296390

Edited 1713351458
Hmmm, ok, i'll try to swap disabled input for readonly/sheetworker calculated, or else i'll start the sheet again Thanks for the advices, yeah i already hide big parts of the sheet depending on tabs and with the use of CSS (:has() support have been a huge help) What is an " attack of divitis" ? The usage of excessive divs with only one element ? If it's that, yeah it might be at some places, i didn't have a huge html/css background before so i completed my knowledge on the way but i know it's not perfect, i'll try to clean it if i find some more but it's a long process
1713310880

Edited 1713310899
GiGs
Pro
Sheet Author
API Scripter
Groch said: What is an " attack of divitis" ? The usage of excessive divs with only one element ? It's exactly that, or less sarcastically, just using more html elements than you need to. Lots of html elements can add to the "cost" of a sheet, though it'll take a lot to make an impact.
1713314335
Andrew R.
Pro
Sheet Author
Inflammation of the div, yes. :)
1713351651

Edited 1713359367
I started to swap disabled for readonly, it's a long process but it looks like it's improving slowly i'll keep you updated if it was the whole underlying problem Thanks again for the help and explanation (i'll try to fight this divitis, need to sharpen my html blade :p) Edit: Ok, i removed most of the "disabled" autocalc inputs, it's now WAAAAAY faster ! i forgot that i had multiples of these hidden depending on some configuration ...
1713366355
GiGs
Pro
Sheet Author
API Scripter
Groch said: Ok, i removed most of the "disabled" autocalc inputs, it's now WAAAAAY faster ! i forgot that i had multiples of these hidden depending on some configuration ... There must have been a lot of them! They are less efficient and more prone to create lag than sheet workers, but you normally need a lot of them to see much effect. Anyway, congratulations! That must be nice.
Yeah with what was hidden depending on config, i had like 30+ auto-calc fields per item inside the repeatable section, so it's a HUGE improvement x) (like going from 2+sec twice per change to 200ms twice per change on the bigger sheets) Now that i have some way to improve on that side, i started to think if sheet load time can be improved too, empty sheets load in like 2 to 4 sec, but players which had set up many charms (powers in Exalted setting) have a significant increase on the load time, like 10 to 15sec No auto-calc in these items only data for the charms so i don't know if i can do something ... Any ideas on this topic ?
1713383633
GiGs
Pro
Sheet Author
API Scripter
That's a crazy long time. Can you post the code for the charms section? By the way, autocalcs always function, on every page load or refresh. Every time you do anything on the sheet, all auto-calcs fire, even if they are hidden. By contrast, sheet workers only fire when the attributes listed in the on('change;' part actually change, so they don't fire anywhere near as often.
1713403614

Edited 1713405725
Ok, thanks for the auto-calc info, i ended assuming this too thats why i'm converting all to readonly, but it's a long task x) For the charms, before posting it i have to explain a bit, Exalted 3e is a complex system so there is many tabs but i will list only the ones usefull here one to configure the charms (name, multiple costs, type of action, long &amp; short desc, effect, and more ... you can include Roll20 expr/macro in some, like cost, because i coded a diceroller script/mod that also remove ressource consumed, and more ... told you i was a madman) then, because Exalted is complex, and charms can be combined depending on ... many things xD, i did a "reminder" area where charms can be seen on other tabs but only their name, cost, type of action icon, a short desc, and the cast buttons these can be found on : the dice roller UI tab : provide a live visual feedback to the players on how much power they can add to the roll and how many dice&amp;successes the roll is gonna send the combat tab :&nbsp; provide also a dice roller UI but more configurable to include Roll20 macros so you can adjust more in-depth but without live visual feedback so, yeah, the repeating_charms-all is included 3 times ... ^^' the config part : &lt;fieldset class="repeating_charms-all" style="display: none;"&gt; &lt;input type="hidden" name="attr_isEvoc" class="sheet-tab-charms-inside-check" value=""&gt; &lt;input type="hidden" name="attr_charm-skill" class="sheet-tab-charms-inside-check" value=""&gt; &lt;input type="hidden" name="attr_charm-name" class="sheet-tab-charms-name-check" value=""&gt; &lt;div class="flex flex-col sheet-body"&gt; &lt;div class="flex flex-wrap"&gt; &lt;input type="hidden" name="attr_charm-learnt" class="charm-learnt-check" value="1"&gt; &lt;input type="text" name="attr_charm-name" class="sheet-charms-spells-trait-name" placeholder="Excellent Solar Larceny"&gt;&lt;span&gt; &lt;/span&gt; &lt;select name="attr_charm-type" style="width: 109px"&gt; &lt;option value=""&gt;&lt;/option&gt; &lt;option value="Simple"&gt;Simple&lt;/option&gt; &lt;option value="Supplemental"&gt;Supplemental&lt;/option&gt; &lt;option value="Reflexive"&gt;Reflexive&lt;/option&gt; &lt;option value="Double"&gt;Suppl. ou Reflex.&lt;/option&gt; &lt;option value="Permanent"&gt;Permanent&lt;/option&gt; &lt;option value="Enchantment"&gt;Enchantment&lt;/option&gt; &lt;/select&gt; &lt;div class="flex grow-normal"&gt;&lt;label&gt;&lt;span&gt;Cost: &lt;/span&gt;&lt;input type="text" name="attr_charm-cost" class="sheet-charms-spells-trait sheet-charms-spells-trait-cost" placeholder="1m/die"&gt;&lt;/label&gt;&lt;/div&gt; &lt;input type="hidden" name="attr_charm-buttons-isextended" class="charm-buttons-include-check" value="0"&gt; &lt;input type="hidden" name="attr_rep-cost-macro"&gt; &lt;div class="charm-buttons charm-buttons-show-default sheet-grouped-buttons"&gt; &lt;button type="roll" class="sheet-roll btn ui-draggable default-whisper" name="act_charmcast" value="&amp;amp;{template:exalted3e_cast} {{charm-name=@{charm-name}}} {{show-character-name=@{show_character_name}}} {{character-name=@{character_name}}} {{aspect=@{charm-aspect}}} {{balanced=@{charm-balanced}}} {{skill=@{charm-skill}}} {{keywords=@{charm-keywords}}} {{type=@{charm-type}}} {{cost=@{charm-cost}}} {{duration=@{charm-duration}}} {{description=@{charm-description}}} {{effect=@{charm-effect}}} {{mute=@{charm-mute}}}\n!exr @{rep-cost-macro}"&gt;Cast&lt;/button&gt; &lt;button type="roll" class="sheet-roll btn ui-draggable gm-whisper" name="act_charmcast-gm" value="/w gm &amp;amp;{template:exalted3e_cast} {{charm-name=@{charm-name}}} {{show-character-name=@{show_character_name}}} {{character-name=@{character_name}}} {{aspect=@{charm-aspect}}} {{balanced=@{charm-balanced}}} {{skill=@{charm-skill}}} {{keywords=@{charm-keywords}}} {{type=@{charm-type}}} {{cost=@{charm-cost}}} {{duration=@{charm-duration}}} {{description=@{charm-description}}} {{effect=@{charm-effect}}} {{mute=@{charm-mute}}}\n!exr @{rep-cost-macro}"&gt;to GM&lt;/button&gt; &lt;button type="roll" class="sheet-roll btn ui-draggable" name="act_charmcast-show" value="&amp;amp;{template:exalted3e_cast} {{charm-name=@{charm-name}}} {{show-character-name=@{show_character_name}}} {{character-name=@{character_name}}} {{aspect=@{charm-aspect}}} {{balanced=@{charm-balanced}}} {{skill=@{charm-skill}}} {{keywords=@{charm-keywords}}} {{type=@{charm-type}}} {{cost=@{charm-cost}}} {{duration=@{charm-duration}}} {{description=@{charm-description}}} {{effect=@{charm-effect}}} {{mute=@{charm-mute}}}" title="Cast the Charm without the cost nor the macro"&gt;Show&lt;/button&gt; &lt;/div&gt; &lt;div class="charm-buttons charm-buttons-show-extended sheet-grouped-buttons"&gt; &lt;button type="roll" class="sheet-roll btn ui-draggable default-whisper" name="act_charmcast-ex" value="&amp;amp;{template:exalted3e_cast} {{charm-name=@{charm-name}}} {{show-character-name=@{show_character_name}}} {{character-name=@{character_name}}} {{aspect=@{charm-aspect}}} {{balanced=@{charm-balanced}}} {{skill=@{charm-skill}}} {{keywords=@{charm-keywords}}} {{type=@{charm-type}}} {{cost=@{charm-cost}}} {{duration=@{charm-duration}}} {{description=@{charm-description}}} {{effect=@{charm-effect}}} {{mute=@{charm-mute}}}\n@{charm-rollexpr} @{rep-cost-macro}"&gt;Cast&lt;/button&gt; &lt;button type="roll" class="sheet-roll btn ui-draggable gm-whisper" name="act_charmcast-ex-gm" value="/w gm &amp;amp;{template:exalted3e_cast} {{charm-name=@{charm-name}}} {{show-character-name=@{show_character_name}}} {{character-name=@{character_name}}} {{aspect=@{charm-aspect}}} {{balanced=@{charm-balanced}}} {{skill=@{charm-skill}}} {{keywords=@{charm-keywords}}} {{type=@{charm-type}}} {{cost=@{charm-cost}}} {{duration=@{charm-duration}}} {{description=@{charm-description}}} {{effect=@{charm-effect}}} {{mute=@{charm-mute}}}\n@{charm-rollexpr} -gm @{rep-cost-macro}"&gt;to GM&lt;/button&gt; &lt;button type="roll" class="sheet-roll btn ui-draggable" name="act_charmcast-show" value="&amp;amp;{template:exalted3e_cast} {{charm-name=@{charm-name}}} {{show-character-name=@{show_character_name}}} {{character-name=@{character_name}}} {{aspect=@{charm-aspect}}} {{balanced=@{charm-balanced}}} {{skill=@{charm-skill}}} {{keywords=@{charm-keywords}}} {{type=@{charm-type}}} {{cost=@{charm-cost}}} {{duration=@{charm-duration}}} {{description=@{charm-description}}} {{effect=@{charm-effect}}} {{mute=@{charm-mute}}}" title="Cast the Charm without the cost nor the macro"&gt;Show&lt;/button&gt; &lt;/div&gt; &lt;input type="text" name="attr_charm-short-desc" class="sheet-charms-spells-trait sheet-charms-spells-trait-short-desc" placeholder="short desc"&gt; &lt;input type="checkbox" name="attr_charm-learnt" class="sheet-charms-spells-trait sheet-charms-spells-trait-learnt" title="Learnt" value="1" checked&gt; &lt;/div&gt; &lt;div class="sheet-table-row" style="width: 100%"&gt; &lt;input type="checkbox" name="attr_charm-effect-display" class="sheet-charmeffect" value="1"&gt;&lt;span class="sheet-charmeffect" title="Show Description &amp;amp; Effect"&gt;&lt;/span&gt; &lt;div class="sheet-charm-effect"&gt; &lt;div class="flex grow-max"&gt;&lt;label&gt;&lt;span&gt;Book: &lt;/span&gt;&lt;input type="text" name="attr_charm-book" class="sheet-charms-spells-trait grow-normal" placeholder="Core"&gt;&lt;span&gt; &lt;/span&gt;&lt;/label&gt;&lt;/div&gt; &lt;div class="flex"&gt;&lt;label&gt;&lt;span&gt;Page #: &lt;/span&gt;&lt;input type="number" name="attr_charm-page" class="sheet-charms-spells-trait" placeholder="255"&gt;&lt;span&gt; &lt;/span&gt;&lt;/label&gt;&lt;/div&gt; &lt;div class="flex"&gt;&lt;label&gt;&lt;span&gt;Duration: &lt;/span&gt;&lt;input type="text" name="attr_charm-duration" class="sheet-charms-spells-trait" placeholder="Instant"&gt;&lt;span&gt; &lt;/span&gt;&lt;/label&gt;&lt;/div&gt; &lt;div class="flex trait-div"&gt;&lt;label&gt;&lt;span class="default-trait"&gt;Trait: &lt;/span&gt;&lt;span class="artifact-trait"&gt;Artifact Name: &lt;/span&gt;&lt;input type="text" name="attr_charm-skill" class="sheet-charms-spells-trait" placeholder="Fire form"&gt;&lt;span&gt; &lt;/span&gt;&lt;/label&gt;&lt;/div&gt; &lt;div class="flex grow-max"&gt;&lt;label&gt;&lt;span&gt;Keywords: &lt;/span&gt;&lt;input type="text" name="attr_charm-keywords" class="sheet-charms-spells-trait grow-normal" placeholder="Uniform, Psyche"&gt;&lt;/label&gt;&lt;/div&gt; &lt;label title="Mute"&gt;&lt;span&gt;Mute: &lt;/span&gt;&lt;div class="flex"&gt;&lt;input type="checkbox" name="attr_charm-mute" class="sheet-charms-spells-trait" value="1"&gt;&lt;/div&gt;&lt;/label&gt; &lt;div class="flex grow-normal"&gt;&lt;label&gt;&lt;span class="show-to-db-only"&gt;Aspect: &lt;/span&gt;&lt;select name="attr_charm-aspect" class="show-to-db-only sheet-charms-spells-trait grow-normal"&gt;&lt;option value="unknown" hidden&gt;Unknown&lt;/option&gt;&lt;option value="none"&gt;None&lt;/option&gt;&lt;option value="air"&gt;Air&lt;/option&gt;&lt;option value="earth"&gt;Earth&lt;/option&gt;&lt;option value="fire"&gt;Fire&lt;/option&gt;&lt;option value="water"&gt;Water&lt;/option&gt;&lt;option value="wood"&gt;Wood&lt;/option&gt;&lt;option value="dawn" hidden&gt;Dawn&lt;/option&gt;&lt;option value="zenith" hidden&gt;Zenith&lt;/option&gt;&lt;option value="twilight" hidden&gt;Twilight&lt;/option&gt;&lt;option value="night" hidden&gt;Night&lt;/option&gt;&lt;option value="eclipse" hidden&gt;Eclipse&lt;/option&gt;&lt;option value="full moon" hidden&gt;Full Moon&lt;/option&gt;&lt;option value="changing moon" hidden&gt;Changing Moon&lt;/option&gt;&lt;option value="no moon" hidden&gt;No Moon&lt;/option&gt;&lt;option value="casteless" hidden&gt;Casteless&lt;/option&gt;&lt;option value="journeys" hidden&gt;Journeys&lt;/option&gt;&lt;option value="serenity" hidden&gt;Serenity&lt;/option&gt;&lt;option value="battles" hidden&gt;Battles&lt;/option&gt;&lt;option value="secrets" hidden&gt;Secrets&lt;/option&gt;&lt;option value="endings" hidden&gt;Endings&lt;/option&gt;&lt;option value="adamant" hidden&gt;Adamant&lt;/option&gt;&lt;option value="jade" hidden&gt;Jade&lt;/option&gt;&lt;option value="moonsilver" hidden&gt;Moonsilver&lt;/option&gt;&lt;option value="orichalcum" hidden&gt;Orichalcum&lt;/option&gt;&lt;option value="soulsteel" hidden&gt;Soulsteel&lt;/option&gt;&lt;option value="starmetal" hidden&gt;Starmetal&lt;/option&gt;&lt;option value="daybreak" hidden&gt;Daybreak&lt;/option&gt;&lt;option value="day" hidden&gt;Day&lt;/option&gt;&lt;option value="dusk" hidden&gt;Dusk&lt;/option&gt;&lt;option value="midnight" hidden&gt;Midnight&lt;/option&gt;&lt;option value="moonshadow" hidden&gt;Moonshadow&lt;/option&gt;&lt;option value="defiler" hidden&gt;Defiler&lt;/option&gt;&lt;option value="fiend" hidden&gt;Fiend&lt;/option&gt;&lt;option value="malefactor" hidden&gt;Malefactor&lt;/option&gt;&lt;option value="scourge" hidden&gt;Scourge&lt;/option&gt;&lt;option value="slayer" hidden&gt;Slayer&lt;/option&gt;&lt;option value="blood" hidden&gt;Blood&lt;/option&gt;&lt;option value="breath" hidden&gt;Breath&lt;/option&gt;&lt;option value="flesh" hidden&gt;Flesh&lt;/option&gt;&lt;option value="marrow" hidden&gt;Marrow&lt;/option&gt;&lt;option value="soil" hidden&gt;Soil&lt;/option&gt;&lt;option value="sorceries" hidden&gt;Sorceries&lt;/option&gt;&lt;/select&gt;&lt;/label&gt;&lt;/div&gt; &lt;label title="Balanced"&gt;&lt;span class="show-to-db-only"&gt;Balanced: &lt;/span&gt;&lt;div class="flex"&gt;&lt;input type="checkbox" name="attr_charm-balanced" class="show-to-db-only sheet-charms-spells-trait"&gt;&lt;/div&gt;&lt;/label&gt; &lt;label title="Can Change Aspect"&gt;&lt;span class="show-to-db-only"&gt;Multi: &lt;/span&gt;&lt;div class="flex"&gt;&lt;input type="checkbox" name="attr_charm-can-cycle-aspects" class="show-to-db-only sheet-charms-spells-trait"&gt;&lt;/div&gt;&lt;/label&gt; &lt;div class="cost-section grow-max flex flex-wrap"&gt; &lt;p class="mote-color-down rounded-box grow-double flex caste-have-exc-toggle"&gt; &lt;label&gt;Mote:&lt;input type="text" name="attr_rep-cost-mote" class="sheet-cost-mote grow-normal" title="Cost as Atome of Essence&amp;#013;&amp;#010;You can include roll20 syntax like @{essence} or [[]] for complex configurations"&gt;&lt;/label&gt; &lt;select name="attr_rep-cost-mote-pool"&gt; &lt;option value="?{Spend Peripheral First ?|Yes,1|No,0}" selected&gt;Prompt&lt;/option&gt; &lt;option value="1"&gt;Peripheral&lt;/option&gt; &lt;option value="0"&gt;Personal&lt;/option&gt; &lt;/select&gt; &lt;input type="hidden" name="attr_rep-cost-mote-commit" value="0"&gt; &lt;label title="Commit on Cast ?"&gt;&lt;span&gt;C: &lt;/span&gt;&lt;div class="flex caste-have-exc-toggle"&gt;&lt;input type="checkbox" name="attr_rep-cost-mote-commit" class="sheet-charms-spells-trait" value="1" title="Commit on Cast ?"&gt;&lt;/div&gt;&lt;/label&gt; &lt;/p&gt; &lt;p class="will-color-down rounded-box grow-normal flex"&gt; &lt;label&gt;Will:&lt;input type="text" name="attr_rep-cost-will" class="sheet-cost-will grow-normal" title="Cost as Willpower&amp;#013;&amp;#010;You can include roll20 syntax like @{essence} or [[]] for complex configurations"&gt;&lt;/label&gt; &lt;/p&gt; &lt;p class="init-color-down rounded-box grow-normal flex"&gt; &lt;label&gt;Init:&lt;input type="text" name="attr_rep-cost-init" class="sheet-cost-init grow-normal" title="Cost as Initiative Points&amp;#013;&amp;#010;You can include roll20 syntax like @{essence} or [[]] for complex configurations"&gt;&lt;/label&gt; &lt;/p&gt; &lt;/div&gt; &lt;/div&gt; &lt;div class="sheet-charm-effect"&gt; &lt;textarea name="attr_charm-description" class="desc" placeholder="Harnessing the great power of The Unconquered Sun, Karal focuses his efforts!"&gt;&lt;/textarea&gt; &lt;/div&gt; &lt;div class="sheet-charm-effect"&gt; &lt;textarea name="attr_charm-effect" class="effect" placeholder="Add dice to a Larceny roll"&gt;&lt;/textarea&gt; &lt;/div&gt; &lt;div class="sheet-charm-effect"&gt; &lt;input type="hidden" name="attr_charm-buttons-isextended" class="charm-buttons-include-check" value="0"&gt; &lt;input type="text" name="attr_charm-rollexpr" placeholder="EX: '!exr -setOnce -d 9 -CRStarter @{essence}', '!exr 15# -d 8,9 -r 6 -v', '!exr (10+?{Motes?|5})#+?{Succes ?|0}', ..."/&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/fieldset&gt; (i know the charm_name is included twice but its for a css tricks i use with :has() and i can't figure how to make it work with a tag 2 level downward ... tried many syntax but none works) the "reminders" part (included twice in the sheet, i could include it only once if i change the css to move the div depending on the tab selected, but css is my weakest point T_T) : &lt;fieldset class="repeating_charms-all" style="display: none;"&gt; &lt;input type="hidden" name="attr_isEvoc" class="sheet-tab-charms-inside-check"&gt; &lt;input type="hidden" name="attr_charm-aspect"&gt; &lt;input type="hidden" name="attr_charm-balanced"&gt; &lt;div class="db-aspect-quickshow"&gt; &lt;input type="hidden" name="attr_charm-can-cycle-aspects" value="0"&gt; &lt;button type="action" name="act_change-aspect" class="quick-change-aspect" title="Change Aspect"&gt;&lt;/button&gt; &lt;img class="aspect" /&gt; &lt;img class="balanced" src="<a href="https://s3.amazonaws.com/files.d20.io/images/290329500/ecMmiM8rUcJ-ziYHX9d18w/max.png?1655517656" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/290329500/ecMmiM8rUcJ-ziYHX9d18w/max.png?1655517656</a>" title="Balanced"/&gt; &lt;/div&gt; &lt;input type="hidden" name="attr_charm-learnt" class="charm-learnt-check" value="1"&gt; &lt;input type="text" name="attr_charm-name" class="sheet-tab-charms-name-check" readonly tabindex="-1"&gt; &lt;input type="hidden" name="attr_charm-buttons-isextended" class="charm-buttons-include-check" value="0"&gt; &lt;input type="hidden" name="attr_rep-cost-macro"&gt; &lt;input type="hidden" name="attr_charm-skill" class="sheet-tab-charms-inside-check"&gt; &lt;input type="hidden" name="attr_charm-keywords"&gt; &lt;input type="hidden" name="attr_charm-mute"&gt; &lt;input type="hidden" name="attr_charm-type"&gt; &lt;img class="charm-icon-type"/&gt; &lt;input type="text" name="attr_charm-cost" readonly tabindex="-1"&gt; &lt;input type="hidden" name="attr_charm-duration"&gt; &lt;input type="hidden" name="attr_charm-description"&gt; &lt;input type="hidden" name="attr_charm-effect"&gt; &lt;input type="hidden" name="attr_charm-rollexpr"&gt; &lt;div class="charm-buttons charm-buttons-show-default sheet-grouped-buttons"&gt; &lt;button type="roll" class="sheet-roll btn ui-draggable default-whisper" name="act_charmcast" value="&amp;amp;{template:exalted3e_cast} {{charm-name=@{charm-name}}} {{show-character-name=@{show_character_name}}} {{character-name=@{character_name}}} {{aspect=@{charm-aspect}}} {{balanced=@{charm-balanced}}} {{skill=@{charm-skill}}} {{keywords=@{charm-keywords}}} {{type=@{charm-type}}} {{cost=@{charm-cost}}} {{duration=@{charm-duration}}} {{description=@{charm-description}}} {{effect=@{charm-effect}}} {{mute=@{charm-mute}}}\n!exr @{rep-cost-macro}"&gt;Cast&lt;/button&gt; &lt;button type="roll" class="sheet-roll btn ui-draggable gm-whisper" name="act_charmcast-gm" value="/w gm &amp;amp;{template:exalted3e_cast} {{charm-name=@{charm-name}}} {{show-character-name=@{show_character_name}}} {{character-name=@{character_name}}} {{aspect=@{charm-aspect}}} {{balanced=@{charm-balanced}}} {{skill=@{charm-skill}}} {{keywords=@{charm-keywords}}} {{type=@{charm-type}}} {{cost=@{charm-cost}}} {{duration=@{charm-duration}}} {{description=@{charm-description}}} {{effect=@{charm-effect}}} {{mute=@{charm-mute}}}\n!exr @{rep-cost-macro}"&gt;to GM&lt;/button&gt; &lt;button type="roll" class="sheet-roll btn ui-draggable" name="act_charmcast-show" value="&amp;amp;{template:exalted3e_cast} {{charm-name=@{charm-name}}} {{show-character-name=@{show_character_name}}} {{character-name=@{character_name}}} {{aspect=@{charm-aspect}}} {{balanced=@{charm-balanced}}} {{skill=@{charm-skill}}} {{keywords=@{charm-keywords}}} {{type=@{charm-type}}} {{cost=@{charm-cost}}} {{duration=@{charm-duration}}} {{description=@{charm-description}}} {{effect=@{charm-effect}}} {{mute=@{charm-mute}}}" title="Cast the Charm without the cost nor the macro"&gt;Show&lt;/button&gt; &lt;/div&gt; &lt;div class="charm-buttons charm-buttons-show-extended sheet-grouped-buttons"&gt; &lt;button type="roll" class="sheet-roll btn ui-draggable default-whisper" name="act_charmcast-ex" value="&amp;amp;{template:exalted3e_cast} {{charm-name=@{charm-name}}} {{show-character-name=@{show_character_name}}} {{character-name=@{character_name}}} {{aspect=@{charm-aspect}}} {{balanced=@{charm-balanced}}} {{skill=@{charm-skill}}} {{keywords=@{charm-keywords}}} {{type=@{charm-type}}} {{cost=@{charm-cost}}} {{duration=@{charm-duration}}} {{description=@{charm-description}}} {{effect=@{charm-effect}}} {{mute=@{charm-mute}}}\n@{charm-rollexpr} @{rep-cost-macro}"&gt;Cast&lt;/button&gt; &lt;button type="roll" class="sheet-roll btn ui-draggable gm-whisper" name="act_charmcast-ex-gm" value="/w gm &amp;amp;{template:exalted3e_cast} {{charm-name=@{charm-name}}} {{show-character-name=@{show_character_name}}} {{character-name=@{character_name}}} {{aspect=@{charm-aspect}}} {{balanced=@{charm-balanced}}} {{skill=@{charm-skill}}} {{keywords=@{charm-keywords}}} {{type=@{charm-type}}} {{cost=@{charm-cost}}} {{duration=@{charm-duration}}} {{description=@{charm-description}}} {{effect=@{charm-effect}}} {{mute=@{charm-mute}}}\n@{charm-rollexpr} -gm @{rep-cost-macro}"&gt;to GM&lt;/button&gt; &lt;button type="roll" class="sheet-roll btn ui-draggable" name="act_charmcast-show" value="&amp;amp;{template:exalted3e_cast} {{charm-name=@{charm-name}}} {{show-character-name=@{show_character_name}}} {{character-name=@{character_name}}} {{aspect=@{charm-aspect}}} {{balanced=@{charm-balanced}}} {{skill=@{charm-skill}}} {{keywords=@{charm-keywords}}} {{type=@{charm-type}}} {{cost=@{charm-cost}}} {{duration=@{charm-duration}}} {{description=@{charm-description}}} {{effect=@{charm-effect}}} {{mute=@{charm-mute}}}" title="Cast the Charm without the cost nor the macro"&gt;Show&lt;/button&gt; &lt;/div&gt; &lt;div class="charm-buttons sheet-grouped-buttons charm-button-learn"&gt; &lt;button type="action" name="act_learn-charm" class="sheet-roll btn ui-draggable" title="Learn !"&gt;Learn !&lt;/button&gt; &lt;/div&gt; &lt;input type="text" name="attr_charm-short-desc" readonly tabindex="-1"&gt; &lt;/fieldset&gt; so, yeah, now you see xD, i hope i'm somehow comprehensible, and sorry for the huge code pastes X_x i can remove one reminder, but it's "only" 33% gain, that wont reduce 15s to 3s lol (but that's still the biggest improvement i found) if you have other ideas, it's really appreciated, thanks a lot for your time ! PS: now i read it again, i know you will tell me about the attack of divitis even more x) but learning flex was hard and it's a mistake i'll fix, though do you think it can impact "that much" ? Edit: an idea i have is switch the buttons type from roll to action in the reminders so i "load" data on click each time instead of at sheet load ... that would reduce the count of hidden fields in the reminders but i tested, and it doesn't feel a lot faster (plus it's hard to have consistent time on the loads so some time i think i improved a bit but its only the delay which vary a bit) Edit2: or ... i move my config tab in this "reminder" kinda div (which can be toggled open above the tab selected) and make a "reminder mode" checkbox to change the display of the charm, so i only have 1 repeating section, but it will be a pain in the ass to adapt from what i have .... f*** me xD
1713425290

Edited 1713425477
GiGs
Pro
Sheet Author
API Scripter
I will have a proper look at the&nbsp; code tomorrow, this is just based on a quick glance before bed. I'm not seeing anything in the code that would lead to a big slowdown. If some characters have a LOT of charms, I can see that contributing, but I still wouldn't expect it to have a huge impact - unless you have sheet workers being triggered from those sections, that are not coded very efficiently. There is something going on that I'm not seeing here, if the normal speed is 2-4 seconds-&nbsp; that is already hinting at a significant lag. It should be pretty much instant. Some general notes: By the way, the two fieldsets you have listed have the same class name - in case you don't know, this means they are both the exact same fieldset and you are just deciding which fields to display in each section. Changing the buttons from roll to action shouldn't make much difference. Action buttons are more recent and probably more effective, but the code in a roll button should really only run when the button is pressed, so it's not going to affect a general lag. Your flex items look like this: &lt;div class="flex grow-max"&gt;&lt;label&gt;&lt;span&gt;Book: &lt;/span&gt;&lt;input type="text" name="attr_charm-book" class="sheet-charms-spells-trait grow-normal" placeholder="Core"&gt;&lt;span&gt; &lt;/span&gt;&lt;/label&gt;&lt;/div&gt; That could easily be rewritten to &lt;div class="flex grow-max"&gt; &lt;label&gt; &lt;span&gt;Book: &lt;/span&gt; &lt;input type="text" name="attr_charm-book" class="sheet-charms-spells-trait grow-normal" placeholder="Core"&gt; &lt;span&gt; &lt;/span&gt; &lt;/label&gt; &lt;/div&gt; This kind of thing would make the code more readable. HTML doesn't care about white space (it can add a tiny, tiny bit to the loading time of a sheet, but iit would take hundreds or thousands of lines like this to even start to be noticed, or a cascading effect that is being triggered somehow. As I said, I'm not seeing anything here which would cause the lag unless there is something in the design of splitting a repeating section with the same name that causes lag (I wouldn't expect it to be even the 2-4s you describe though). I'm wondering if there are a lot of sheet workers linked to this section that have a sheet:opened event. If the delay happens mainly when you first open a sheet but not so much when you generally browse a sheet, that's what I'd look for.
Yeah some characters have like 60 to 100 charms, and its going up ^^' yeah i know about the repeating, that's why i choosed to reuse it but with a "lighter" html hoping it wouldn't affect a lot, but my guess was, if its reused elsewhere, maybe roll20 on the client side have a cache and may not re load data from server, so i prayed for this xD On the changing buttons from roll to action, my guess to improve load time is to remove the hidden fields, assuming if they are not included in the html they won't be "loaded", so the "roll" button fail to send datas if they are not present around the button, so with action i "load" the data myself before sending it to the rolltemplate (i tested to remove fields with the "roll" button, and the rolltemplate was showing incorrect data as if data wasn't loading, like "CharacterName?character-attribute" was in most fields in the rolltemplate) For the Flex item, yeah i know but these were "simple divs containing only one cell, only one input", thats why i let them in a line but yeah it makes it less readable, and having "all these lines" only for one input as all other tags around are for styling... i decided to keep it that way ^^' i'll look into the sheet:opened &nbsp;triggers, but what to you mean "linked to this section" ? Anyway, huge thanks again for your help and clues, have a great day !
1713460845
GiGs
Pro
Sheet Author
API Scripter
Groch said: i'll look into the sheet:opened &nbsp;triggers, but what to you mean "linked to this section" ? I mean triggered by this section. on(change: elements pointing at stats in the repreating section or by the repeating section itself.
okay so on:change &nbsp;triggers at opening too ? like it "changes" to the loaded value ?
1713496474

Edited 1713496589
GiGs
Pro
Sheet Author
API Scripter
I'm not sure what you're asking. Every sheet worker sstarts with a trigger or group on triggers, like change:[a stat], clicked:[an action button name], or sheet:opened. Whenever any of these triggers happen, the sheet worker runs. Lots of people put sheet:opened in all of their sheet workers, but it is almost never needed (some sheet workers do need it, but they are a minority). The sheet:opened trigger means to run that sheet worker when the character sheet is opened. If many sheet workers have it, it means many sheet workers run every time the sheet is opened, and the sheet is unresponsive till they all finish - which can mean lots of unnecessary lag. This lag occurs at one specific time: when the sheet is first opened. So if a sheet takes a long time to respond when first opened, but is okay after that, this could be the problem.
1713580433

Edited 1713580524
ok, i tested directly by removing all the sheetworker code, and i gain around 1sec, so it's not the sheet:opened i have some to refresh some calculation and be sure the sheet is up to date but i wasn't sure how much it would impact So ... it's the raw html that takes that much time ... From what you said previously i don't know if there is a cache in the roll20 engine client side, or, do you think removing the 2 others repeating_charms-all would impact a lot ? edit: i'll just test it result, going from 12sec(without script but 3time the repeating section) to 6sec(without script, only once the repeating) So ... i'll finish to remove the disabled, and find a cool way to have only 1 time the repeating section, and it'll be the biggest time save from what we could find, if i didn't forget something.
1713586696
GiGs
Pro
Sheet Author
API Scripter
So, if you can, changing the sheet so it doesn't have multiple copies of the repeating section seems like a very good idea. You mentioned characters have 60-100 charms. Do they need to have them all stored on the sheet? In D&amp;D-style games, characters often have access to many, maybe hundrds, of spells, and very common advice is for players to only add the spells they actually use, to reduce lag. It might be worth storing all the charms in a library sheet you use only for reference, so people can easily copy them as needed, but not store them on their sheets. Other things to try, purely out of desperation: look into stripping anything that doesn't need to be in the charms repeating section and put it somewhere else. Remember, everything in there is being duplicated for every charm created - if there's anything you can take out might significantly reduce the load. You might also want to look into minifying the code (which strips out spaces, linebreaksand other stuff unneccessary for the HTML parser). The resulting sheet ownt be readable,so it would be a good idea to keep a copy of that sheet. I don't know how much difference this will make, if any, really. I'm just suggesting things that might have an effect.
1713625673

Edited 1713625857
GiGs said: I don't know how much difference this will make, if any, really. I'm just suggesting things that might have an effect. Yeah don't worry, i pick every bit i can and try ^^ Sadly, yeah they need their charms because each abilities have their charm tree and that's what they learn and then use depending on ability used (many times in combo with other charms), some player prepare them in advance to specify visual the power takes (and yeah i already did a library kind of stuff extracting all charms from all book, that's why my sheet weight 5Mo X_x there is like 3 or 4Mo of json data from books included lol), and i don't think i've included a lot of "fancy" additions in the charms html that could be stripped from the data structure/attr used edit: ahhhh a library sheet , looks interesting, but there is too many, like 300 in the 1st book, actually there might be more than 1k or 1k5 charms all books included and more to come, so i wouldn't have copied them one by one by hand xD but i could use my JSON to make that character library, and then strip the datas from the sheet, but it added "only" 1 to 2 sec when i added these 3-4Mo of JSON data to the sheet to be used, soooo ... i think i prefer loosing 2sec but have a local library and have a "add selected" action button, which is the only access to these data, as i have now. Well, i'm already looking into a html tree &amp; css adaptation so i only have 1 repeating section of the charms but it'll take some more reflection to finalize even if i found a way ! And for minifying the code, i'll test it in the end after all the above, i know there is like 14k lines overall in the sheet so, might be usefull x)
1713640661

Edited 1713640751
@GiGs said: It looks like you are using Roll20Async to get async functionality. IIRC, for big sheets, this can be very slow - much, much slower than not using it, because it makes many more getAttrs/setAttrs calls than are needed. I think you misremember, Gig.&nbsp; Roll20Async does NOT do this.&nbsp; It just enables async and promises.&nbsp; There should be no performance impacts from using it. I think you are remembering a conversation around an early version of orcsCharacter, which let's you do things like: pc.str = pc.str + pc.healFactor;&nbsp; Once upon a time,&nbsp; that led to chatty client/server interactions, but no more.&nbsp; For a while now that particular module employs caching.&nbsp; So... j ust combatting fake news, here. Cheers!
OnyxRing said: @GiGs said: It looks like you are using Roll20Async to get async functionality. IIRC, for big sheets, this can be very slow - much, much slower than not using it, because it makes many more getAttrs/setAttrs calls than are needed. I think you misremember, Gig.&nbsp; Roll20Async does NOT do this.&nbsp; It just enables async and promises.&nbsp; There should be no performance impacts from using it. I think you are remembering a conversation around an early version of orcsCharacter, which let's you do things like: pc.str = pc.str + pc.healFactor;&nbsp; Once upon a time,&nbsp; that led to chatty client/server interactions, but no more.&nbsp; For a while now that particular module employs caching.&nbsp; So... j ust combatting fake news, here. Cheers! Thanks for the info ! And thanks for your work i use it a lot it's really usefull :)
1713661710
GiGs
Pro
Sheet Author
API Scripter
OnyxRing said: @GiGs said: It looks like you are using Roll20Async to get async functionality. IIRC, for big sheets, this can be very slow - much, much slower than not using it, because it makes many more getAttrs/setAttrs calls than are needed. I think you misremember, Gig.&nbsp; Roll20Async does NOT do this.&nbsp; It just enables async and promises.&nbsp; There should be no performance impacts from using it. That's good to know!