Personally, I think raw callbacks are the right thing 95% of the time. yield/async/coroutines are needed for branching async logic where otherwise you'd be forced to make a new function for each branch and deal with the spaghetti at the end.