To answer your earlier question, this is how I structure my version upgrader. const versionator = version => { console.log("Version Checking.") switch (true) { case !version: case version < 1: update_to_v1(); break; case version < 2: // add another function here when you need it break; case version < 3: // ditto break; default: console.log(`Version Update complete. Version: ${version}.`); } }; on('sheet:opened', () => { getAttrs(['version'], v => { versionator(parseFloat(v.version) || 0); }); }); You have sheet:opened event, which gets the sheet's version, then calls the versionator function. The versionator then checks if the sheet needs to be updated. If it does it calls a function to do the actual updating. This takes us to your last post. To be able to get sheet attributes, you need getAttrs - that's the only way to read attribute values off the sheet. And that takes us back to using fieldnames :) You also have getAttrs outside the getSectionIDs - thats never an efficient way to do it as it means you'll have to use two getAttrs. I;m not entirely sure what's going on in the body of your function so I havent attempted to do that, but here's a framework for how it should be laid out. function update_to_v1() { getSectionIDs("repeating_principles", principlesarray => { getSectionIDs("repeating_powers", powersarray => { getSectionIDs("repeating_qualities", qualitiesarray => { const fieldnames = []; principlesarray.forEach(id => { // empty because i dont know what goes here }); powersarray.forEach(id => { fieldnames.push(`repeating_powers_${id}_powerdtype`); }); qualitiesarray.forEach(id => { fieldnames.push(`repeating_qualities_${id}_qualitydtype`); }); getAttrs(["version","greendtype","yellowdtype","reddtype", ...fieldnames], function(v) { let output = {}; //output.version = 1; //only uncomment this when your worker is fully tested and working. principlesarray.forEach(id => { // do whatever you need to do here. }); powersarray.forEach(id => { }); qualitiesarray.forEach(id => { }); setAttrs(output,
{silent: true},
versionator(update.version))); }); }); }); }); }; notice the setAttrs line. {silent:true} means when setAttrs changes attributes, no sheet workers are triggered. You might want to set that to false if you depend on sheet values changing, but in an update function its best to avoid that because of the asynchronous nature of setAttrs and the fact multiple updates might be triggered simultaneously. There's no guarantee the sheet will update in the correct order, And finally setAttrs has a callback function. This calls the versionator again. This is important if you have a sheet that;s gone through, say, versions 1, 2, and 3, and someone opens their old version 0 sheet after a long time. You need all version updates to be carried out - this callback sends the worker back to the version checking function. At this point the sheet will have been updated to version 1, and if there's a version 2 update, it will now be done as well. The fact it is in the callback of setAttrs means the next version update can only happen after the first update has completed, avoiding the problems with async functions.