Change Future.doWhile to use a loop for non-future results instead of recursion.

Avoids stack overflow on long sequences of non-future results.

R=floitsch@google.com

Review-Url: https://codereview.chromium.org/2853203002 .
This commit is contained in:
Lasse R.H. Nielsen 2017-05-02 12:56:53 +02:00
parent 5389b1114e
commit 8c742bd500
2 changed files with 32 additions and 5 deletions

View file

@ -485,8 +485,10 @@ abstract class Future<T> {
var nextIteration;
// Bind this callback explicitly so that each iteration isn't bound in the
// context of all the previous iterations' callbacks.
// This avoids, e.g., deeply nested stack traces from the stack trace
// package.
nextIteration = Zone.current.bindUnaryCallback((bool keepGoing) {
if (keepGoing) {
while (keepGoing) {
FutureOr<bool> result;
try {
result = f();
@ -500,10 +502,9 @@ abstract class Future<T> {
result.then(nextIteration, onError: doneSignal._completeError);
return;
}
nextIteration(result);
} else {
doneSignal._complete(null);
keepGoing = result;
}
doneSignal._complete(null);
}, runGuarded: true);
nextIteration(true);
return doneSignal;

View file

@ -238,6 +238,30 @@ Future testDoWhileWithException() {
});
}
Future testDoWhileManyFutures() {
int n = 100000;
var ftrue = new Future.value(false);
var ffalse = new Future.value(false);
return Future.doWhile(() {
return (--n > 0) ? ftrue : ffalse;
}).then((_) {
// Success
}, onError: (e, s) {
Expect.fail("$e\n$s");
});
}
Future testDoWhileManyValues() {
int n = 100000;
return Future.doWhile(() {
return (--n > 0);
}).then((_) {
// Success
}, onError: (e, s) {
Expect.fail("$e\n$s");
});
}
main() {
List<Future> futures = new List<Future>();
@ -259,10 +283,12 @@ main() {
futures.add(testDoWhile());
futures.add(testDoWhileSync());
futures.add(testDoWhileWithException());
futures.add(testDoWhileManyFutures());
futures.add(testDoWhileManyValues());
asyncStart();
Future.wait(futures).then((List list) {
Expect.equals(18, list.length);
Expect.equals(20, list.length);
asyncEnd();
});
}