$timeout
calls $apply
which calls $digest
.
In more detail:
$apply
triggers a $digest
cycle on root scope (therefore on all scopes within the application).
$digest
can be called directly on a particular child scope instead of on root -- but watchers on parent or sibling scopes won't be triggered, so incautious use of $digest
can leave different scopes visibly out of synch.
$timeout
waits for the next digest cycle, and then calls $apply
(and thus is basically a simple way to call $apply
without worrying about "digest already in progress" errors.) The newer $evalAsync
is similar but applies to the current digest if possible, so is sometimes slightly more performant than $timeout
. (There is also $applyAsync
which is as far as I can tell basically $timeout
with a 10ms delay, for reasons which I'm sure make sense to someone.)
TL;DR: leave Angular to manage its own data lifecycle as much as possible. When you need to, use $evalAsync
(or, honestly, $timeout
is close enough; the difference is not that significant).
If you start running into performance issues, you can start looking for cases where you can safely switch to using $digest
on specific scopes. (Personally I've not seen many cases where this is worth the added code complexity, but maybe that's just me.)