-
Notifications
You must be signed in to change notification settings - Fork 27.3k
Timeout callback can occur in the middle of a digest cycle in Firefox #10083
Description
It appears that, in Firefox only, certain actions cause it to process the timeout queue on top of the current call stack. If the current call is in a digest cycle, and a $timeout with invokeApply=true gets triggered, this results in a $apply already in progress error.
See http://plnkr.co/edit/9V1jQSaszbjrt9F5ACjk?p=preview for a repro that uses window.open to trigger timeout processing. If you click on the button you'll see the following sequence in the console:
"before window open" script.js:6
"timeout" script.js:5
"Error: [$rootScope:inprog] $apply already in progress
http://errors.angularjs.org/1.3.1/$rootScope/inprog?p0=%24apply
minErr/<@http://code.angularjs.org/1.3.1/angular.js:80:12
beginPhase@http://code.angularjs.org/1.3.1/angular.js:14463:1
$RootScopeProvider/this.$get</Scope.prototype.$apply@http://code.angularjs.org/1.3.1/angular.js:14207:11
timeout/timeoutId<@http://code.angularjs.org/1.3.1/angular.js:15945:25
completeOutstandingRequest@http://code.angularjs.org/1.3.1/angular.js:4842:7
Browser/self.defer/timeoutId<@http://code.angularjs.org/1.3.1/angular.js:5215:7
$scope.click@http://run.plnkr.co/AFImpHzuwgSHuYUW/script.js:7:5
$parseFunctionCall@http://code.angularjs.org/1.3.1/angular.js:12114:15
ngEventHandler/</callback@http://code.angularjs.org/1.3.1/angular.js:22548:17
$RootScopeProvider/this.$get</Scope.prototype.$eval@http://code.angularjs.org/1.3.1/angular.js:14110:16
$RootScopeProvider/this.$get</Scope.prototype.$apply@http://code.angularjs.org/1.3.1/angular.js:14208:18
ngEventHandler/<@http://code.angularjs.org/1.3.1/angular.js:22553:17
createEventHandler/eventHandler@http://code.angularjs.org/1.3.1/angular.js:2979:9
" angular.js:11339
"after window open"
Tested on Firefox 33.1.1 in Windows 7 and OS X with Angular 1.3.1, but I've observed the same thing on older versions of both Firefox and Angular so it's not a regression. I used window.open to trigger timeout processing for the repro but I have reason to believe that other operations can do it too. I haven't seen this happen in Chrome or any other browser.
I don't know the formal spec of setTimeout well enough to guess whether this is a bug in Firefox or not, but in either case it seems like something that's worth guarding against in Angular.