One thing that's certainly not that clear enough about callbacks is what happens with regular postback events and control state. During a callback, we reconstruct the state of the page as it was during the last postback. The reason we are doing this is that we want the logic in the callback method to be able to access the rest of the page with controls in the right state.
We don't update the ViewState during a callback because we allow for parallel callbacks (by the way, don't let the "useAsync" parameter of GetCallbackEventReference fool you: it's really about parallel or sequential). If we had both parallel callbacks and ViewState updating, the page would easily get to an inconsistent state. What control developers do to work around this problem is to store the client-side and callback state changes for their control in a separate hidden field and replay these changes server-side on the next postback. This adds a little complexity to controls such as the TreeView.
But how are we maintaining the last postback state during callbacks? One of the first things the WebForms client script does in a callback page is to initialize an object and store the contents of the form in it, before it can be modified. This object will be sent back to the server with the callback parameters. It means that your network payload is more important than just your parameters but that's the price of statefulness (more on this later). When we receive the callback server-side, this enables us to reconstruct the state of the page as it was during the last postback (which is the last consistent state we know). We don't want the actual state of the form at the time the callback was made because this state might be inconsistent (because of validated fields and so on). If you want a perfectly up-to-date version of a form field (and not just state data), it means that it is really a parameter of your callback and should be transmitted as such.
I know this needs a little getting used to (I needed it myself), but it also raises a question: if the state is reconstructed exactly like it was during the last postback, and if an event (for example a click event or a textbox change event) happened during the last postback, will this event be re-triggered on each callback?
The answer is no. To trigger a click event, depending on the button being a regular button, an image button or a link button, we look at the form field for this button or at a special hidden field pair. Both of these are stateless, which means that even if their value is non-empty during the server postback, once they get back to the client, they are empty again. Thus, when we send the initial form state during a callback, these fields will be empty and the event will not be triggered again. For a textbox change event, it's a little different. The change event compares the actual value of the form field with the last value it stored in ViewState. During a callback, we get the initial value, which is identical to the value in ViewState because the latter was stored at the end of the last postback, after change events. So no change event, except if you disabled ViewState (but it's the same thing with postbacks). Which is one more reason why we don't want the updated value of the field at this time: we don't want the change event to be triggered during every callback until the next postback.