Well, it's more complicated than that, because the Sheet Workers are themselves calling back to the main thread to do things like fetch or set attributes. Assume each line break is the end of a stack where main thread will move on to something else, and where I use -> are places that the main thread is "locked" so it will be guaranteed to happen immediately in the same call stack. If I used the same number twice, it indicates that there are two separate threads operating at the same time, so these things will be happening simultaneously: 1. [main] atrr1.setWithWorker() -> set() (values changed) -> generate message to send to sheet workers 2. [sw] receive message, trigger callbacks, callback calls getAttrs() -> send message to [main] requesting attribute values 2. [main] attr2.setWithWorker() -> set() -> generate message to send to sheet workers 3. [sw] receive message from attr2.setWithWorker(), trigger callback, callback calls getAttrs() -> send message to [main] requesting attribute values ...at this point assume you had nothing else you had called on the main thread in your script. 4. [main] respond to getAttrs() call via a message event from [sw], do findObj(), send message back to [sw] with results from findObj() 5. [sw] receive response to first getAttrs() call, further processing, callback calls setAttrs() 5. [main] respond to second getAttrs() call via a message event from [sw], do findObj(), send message back to [sw] with results from findObj() 6. [main] respond to setAttrs() call from [sw], call setWithWorker() -> set() -> (if silent, stop) -> tell [sw] we've set attributes 6. [sw] receive response to second getAttrs() call, further processing, callback calls setAttrs() 7. [main] respond to second setAttrs() call from [sw], call setWithWorker() -> set() -> (if silent, stop) -> tell [sw] we've set attributes 7. [sw] respond to notification attributes were set from first setAttrs() call ...etc. So, to answer your questions based on that: Lucian said: To be 100% clear, when I do setWithWorker, does that immediately start stuff off in the worker thread, even before the main thread returns? Although I don't believe it's relevant to the problem in hand, I do think there are potential issues with this, in that it becomes impossible to set multiple attributes in an atomic operation, which could easily leads to all manner of unexpected/undesirable behaviour. The main thread would process the setWithWorker(), which would set the actual value immediately. Then it would generate a message to notify the sheetworker thread that the values have changed. It would send that message. Then it would move immediately onto it's next instruction, which is to do the second setWithWorker() call. So all setWithWorker() calls in a row on the main thread would process prior to the first execution of the sheet worker being able to do anything, since the sheetworker would have to wait for the main thread to become "free" before it can do anything. Since the sheetworker always has to wait on the main thread to anything but logic (e.g. get an attribute, set an attribute), you can guarantee that things will happen in the correct order. So thinking about this, I actually do think it would work the way that you're suggesting in the last part of your post. I think the problem is that if we take my example above and insert an expensive operation between 3 and 4, the sheet worker would be sitting idly and the timeout would fire when the main thread resumes. I think I can switch it to a method where when it thinks the timeout should fire, it instead gives the main thread a chance to complete all current operations it wants to call, and then it should be fine. So I will try that instead. Hope that helps clear it up.