Comparing item_done() to apply() has a bit of the apples to oranges problem. Remember that item_done() occurs when the request sent over to the driver is completed (or more accurately, when the driver calls item_done). Item_done does not indicate a response. Apply is a two-way communication: it sends a request over, and gets a response back. The equivalent of item_done would be somewhere in between those two.
So, the apply() will return after the driver has done a get_next_item(req), followed by a put_rsp.put(rsp). Only when the response has returned does apply() return.
A more apples-to-apples comparison would be item_done and apply_send (which will send a request over, but it will not wait for a response). In that case, the apply_send will wait until the driver is ready to accept the item from this sequence before randomizing, and it will return after the driver has completed the call get_next_item(). However, any subsequent call to any apply will always wait until the driver has issues a get_next_item, and this particular sequence has been chosen by the sequencer.
In all cases, this ensures that the item is sent (and randomization is done) immediately before the driver gets the item, rather than when the apply is called.