Looking at Angular source code, it looks like $timeout makes a call to
$rootScope.$apply().
- Why doesn't $timeout() also raise an error if a digest cycle is already in progress?
$timeout
makes use of an undocumented Angular service $browser
. Specifically it uses $browser.defer()
that defers execution of your function asynchronously via window.setTimeout(fn, delay)
, which will always run outside of Angular life-cycle. Only once window.setTimeout
has fired your function will $timeout
call $rootScope.$apply()
.
- Is the best practice to use $scope.$apply() when you know for sure that a digest won't already be in progress and $timeout() when needing it to be safe either way?
I would say so. Another use case is that sometimes you need to access a $scope variable that you know will only be initialized after digest. Simple example would be if you want to set a form's state to dirty inside your controller constructor (for whatever reason). Without $timeout the FormController
has not been initialized and published onto $scope, so wrapping $scope.yourform.setDirty()
inside $timeout ensures that FormController
has been initialized. Sure you can do all this with a directive without $timeout, just giving another use case example.
- Is $timeout() really an acceptable "safe apply", or are there gotchas?
It should always be safe, but your go to method should always aim for $apply() in my opinion. The current Angular app I'm working on is fairly large and we've only had to rely on $timeout once instead of $apply().
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…