Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Infinite $digest caused by deferred/promise #2622

Closed
tdterry opened this issue May 9, 2013 · 10 comments
Closed

Infinite $digest caused by deferred/promise #2622

tdterry opened this issue May 9, 2013 · 10 comments

Comments

@tdterry
Copy link

tdterry commented May 9, 2013

I have found an infinite $digest loop caused by using a deferred inside a deferred. The jsfiddle link below demonstrates the problem. I have purposefully broken the link to angular so you can load the fiddle without hanging the browser. Simple change the link to angular in the HTML pane, and remove the alert in the JS pane.

http://jsfiddle.net/tdterry/yfytc/1/

This is a barebones example of a legitimate use case I have where one deferred property depends on another deferred property. It's the combination of creating the deferred, resolving it, and acting on the promise that causes the hang. If you comment out either line 14 or 15 in the JS, it doesn't hang.

Also, this does NOT hang in 1.0.6.

@tdterry
Copy link
Author

tdterry commented May 9, 2013

Browsers tested: Chrome 26.0.1410.65 and Safari 6.0.4 (8536.29.13)

@panth77
Copy link

panth77 commented May 9, 2013

+1 Confirmed in Firefox 20.0 as well. Works as intended using angular 1.0.6.

@tdterry
Copy link
Author

tdterry commented May 9, 2013

I tracked the cause down to this commit:

331cd5a

.then() calls are processed asynchronously using the asyncQueue. In 1.1.4, there is a single global $rootScope.$$asyncQueue, so every time through $digest, the inner deferred adds another item on the queue. This was not a problem in 1.0.x because the asyncQueue used by the deferred was not the same one that $digest was trying to empty.

This is not to say that commit was wrong, but with a single async queue, maybe the deferred handling needs to be updated, or maybe digest should have a limit on the number of times it tries to empty the queue.

@blandinw
Copy link

blandinw commented Jul 1, 2013

+1, same problem when switching from 1.0.7 to 1.1.5.

@tdterry
Copy link
Author

tdterry commented Aug 26, 2013

Any chance someone can revisit this after 1.2?

@IgorMinar
Copy link
Contributor

The example in the plunker breaks a core rule of angular's data-binding - the expression used in data-binding should be idempotent (have no side-effect). In the fiddle, you define a getter who whenever called, creates a new promise, resolves it and by doing so has side-effects. A better question is why doesn't angular break after 10 cycles, just like it does in other cases when we detect an infinite digest. That is a bug that should be fixed.

@sinelaw
Copy link
Contributor

sinelaw commented Dec 30, 2013

Any news on fixing this (i.e. throwing an exception)? Using 1.2.6 here.

sinelaw added a commit to bdb-opensource/angular.js that referenced this issue Dec 30, 2013
…yncQueue is empty when decrementing ttl

An infinite $digest loop can be caused by expressions that invoke a promise. The problem is that $digest does not
decrement ttl unless it finds dirty changes; it should check also if asyncQueue is empty.
Generally the condition for decrementing ttl should be the same as the condition for terminating the $digest loop.

Closes angular#2622
@ghost ghost assigned tbosch Dec 31, 2013
@tbosch
Copy link
Contributor

tbosch commented Dec 31, 2013

Note: The Commit above implement the suggestion from Igor to correctly throw an error.

@tbosch
Copy link
Contributor

tbosch commented Dec 31, 2013

The issue is still existing in angular master.

sinelaw added a commit to bdb-opensource/angular.js that referenced this issue Dec 31, 2013
…yncQueue is empty when decrementing ttl

An infinite $digest loop can be caused by expressions that invoke a promise. The problem is that $digest does not
decrement ttl unless it finds dirty changes; it should check also if asyncQueue is empty.
Generally the condition for decrementing ttl should be the same as the condition for terminating the $digest loop.

Closes angular#2622
jeffbcross pushed a commit to jeffbcross/angular.js that referenced this issue Jan 10, 2014
…s empty when decrementing ttl

An infinite $digest loop can be caused by expressions that invoke a promise.
The problem is that $digest does not decrement ttl unless it finds dirty changes;
it should check also if asyncQueue is empty.
Generally the condition for decrementing ttl should be the same as the
condition for terminating the $digest loop.

Closes angular#2622
jeffbcross pushed a commit to jeffbcross/angular.js that referenced this issue Jan 10, 2014
…s empty when decrementing ttl

An infinite $digest loop can be caused by expressions that invoke a promise.
The problem is that $digest does not decrement ttl unless it finds dirty changes;
it should check also if asyncQueue is empty.
Generally the condition for decrementing ttl should be the same as the
condition for terminating the $digest loop.

Closes angular#2622
jeffbcross pushed a commit to jeffbcross/angular.js that referenced this issue Jan 10, 2014
…s empty when decrementing ttl

An infinite $digest loop can be caused by expressions that invoke a promise.
The problem is that $digest does not decrement ttl unless it finds dirty changes;
it should check also if asyncQueue is empty.
Generally the condition for decrementing ttl should be the same as the
condition for terminating the $digest loop.

Fixes angular#2622
@Narretz
Copy link
Contributor

Narretz commented Jan 12, 2014

addressed by (umerged) #5578

jamesdaily pushed a commit to jamesdaily/angular.js that referenced this issue Jan 27, 2014
…s empty when decrementing ttl

An infinite $digest loop can be caused by expressions that invoke a promise.
The problem is that $digest does not decrement ttl unless it finds dirty changes;
it should check also if asyncQueue is empty.
Generally the condition for decrementing ttl should be the same as the
condition for terminating the $digest loop.

Fixes angular#2622
jamesdaily pushed a commit to jamesdaily/angular.js that referenced this issue Jan 27, 2014
…s empty when decrementing ttl

An infinite $digest loop can be caused by expressions that invoke a promise.
The problem is that $digest does not decrement ttl unless it finds dirty changes;
it should check also if asyncQueue is empty.
Generally the condition for decrementing ttl should be the same as the
condition for terminating the $digest loop.

Fixes angular#2622
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.