Hopefully my last post for a while, but wanting to be cheeky and check that i've applied my lessons correctly from previous responses in this forum before I go all in on refactoring all my (applicable) sheetworkers to operate in this way. Context around the example, the speed of weapon attacks is dependant on the speed of the user & the speed modifier of the weapon. Inside the repeating section "repeating_attacks" both the attackspeedmod and attackspeed are recorded for use by attack rolls. In the below example both the old and new versions of this sheetworker worked , as in they both output the desired result. The old version had multiple problems though, getAttrs/setAttrs inside for loops etc. The new version includes as many lessons learned as I can muster so as to avoid the many foibles and pitfalls of asynchronous functions. New (hopefully all cleaned up): //When shell_speed changes, attackspeedmod changes or attackname changes update calculated attack speeds within repeating section. on ( "change:shell_speed change:repeating_attacks:attackspeedmod change:repeating_attacks:attackname" , function () { getSectionIDs ( "repeating_attacks" , function ( ids ) { //init array to hold attribute list with default value of needed global attribute. let attributes = [ "shell_speed" ]; //for each row, get the rowid to retrieve relevant repeating attributes and push attribute names to an array. ids . forEach ( rowid => { let speedmodattr = `repeating_attacks_ ${ rowid } _attackspeedmod` ; let attackspeedattr = `repeating_attacks_ ${ rowid } _attackspeed` ; attributes . push ( speedmodattr , attackspeedattr ); }) //get all requested attributes. getAttrs ( attributes , function ( values ) { const shellspeed = parseInt ( values . shell_speed )|| 3 ; //group results by rowid & build final object. setObj = ids . reduce (( results , rowid ) => { let speedmodattr = `repeating_attacks_ ${ rowid } _attackspeedmod` ; let speedmod_value = parseInt ( values [ speedmodattr ])|| 0 ; let attackspeedattr = `repeating_attacks_ ${ rowid } _attackspeed` ; let attackspeed_value = shellspeed + speedmod_value ; if ( attackspeed_value < 1 ) { attackspeed_value = 1 ; } else if ( attackspeed_value > 5 ) { attackspeed_value = 5 ; } results [ attackspeedattr ] = attackspeed_value return results ; }, {}); setAttrs ( setObj ); }); }); });