@@ -235,7 +235,7 @@ abstract interface class Future<T> {
235235 static final _Future <void > _nullFuture = nullFuture as _Future <void >;
236236
237237 /// A `Future<bool>` completed with `false` .
238- static final _Future <bool > _falseFuture = new _Future <bool >.zoneValue (
238+ static final _Future <bool > _falseFuture = _Future <bool >.zoneValue (
239239 false ,
240240 _rootZone,
241241 );
@@ -253,7 +253,7 @@ abstract interface class Future<T> {
253253 /// If a non-future value is returned, the returned future is completed
254254 /// with that value.
255255 factory Future (FutureOr <T > computation ()) {
256- _Future <T > result = new _Future <T >();
256+ _Future <T > result = _Future <T >();
257257 Timer .run (() {
258258 FutureOr <T > computationResult;
259259 try {
@@ -280,7 +280,7 @@ abstract interface class Future<T> {
280280 /// If calling [computation] returns a non-future value,
281281 /// the returned future is completed with that value.
282282 factory Future .microtask (FutureOr <T > computation ()) {
283- _Future <T > result = new _Future <T >();
283+ _Future <T > result = _Future <T >();
284284 scheduleMicrotask (() {
285285 FutureOr <T > computationResult;
286286 try {
@@ -314,7 +314,7 @@ abstract interface class Future<T> {
314314 try {
315315 result = computation ();
316316 } catch (error, stackTrace) {
317- var future = new _Future <T >();
317+ var future = _Future <T >();
318318 _asyncCompleteWithErrorCallback (future, error, stackTrace);
319319 return future;
320320 }
@@ -349,7 +349,7 @@ abstract interface class Future<T> {
349349 @pragma ("vm:entry-point" )
350350 @pragma ("vm:prefer-inline" )
351351 factory Future .value ([FutureOr <T >? value]) {
352- return new _Future <T >.immediate (value == null ? value as T : value);
352+ return _Future <T >.immediate (value == null ? value as T : value);
353353 }
354354
355355 /// Creates a future that completes with an error.
@@ -371,7 +371,7 @@ abstract interface class Future<T> {
371371 /// ```
372372 factory Future .error (Object error, [StackTrace ? stackTrace]) {
373373 AsyncError (: error, : stackTrace) = _interceptUserError (error, stackTrace);
374- return new _Future <T >.immediateError (error, stackTrace);
374+ return _Future <T >.immediateError (error, stackTrace);
375375 }
376376
377377 /// Creates a future that runs its computation after a delay.
@@ -390,7 +390,7 @@ abstract interface class Future<T> {
390390 /// If [computation] is omitted,
391391 /// it will be treated as if [computation] was `() => null` ,
392392 /// and the future will eventually complete with the `null` value.
393- /// In that case, [T] must be nullable.
393+ /// In that case, [T] ** must** be nullable.
394394 ///
395395 /// If calling [computation] throws, the created future will complete with the
396396 /// error.
@@ -405,28 +405,32 @@ abstract interface class Future<T> {
405405 /// });
406406 /// ```
407407 factory Future .delayed (Duration duration, [FutureOr <T > computation ()? ]) {
408- if (computation == null && ! typeAcceptsNull <T >()) {
409- throw ArgumentError .value (
410- null ,
411- "computation" ,
412- "The type parameter is not nullable" ,
413- );
414- }
415408 _Future <T > result = _Future <T >();
416- new Timer (duration, () {
417- if (computation == null ) {
418- result._complete (null as T );
409+ if (computation == null ) {
410+ const T ? defaultResult = null ;
411+ if (defaultResult is T ) {
412+ result._zone.createTimer (duration, () {
413+ result._complete (defaultResult);
414+ });
419415 } else {
416+ throw ArgumentError (
417+ "Required when the type parameter is not nullable" ,
418+ "computation" ,
419+ );
420+ }
421+ } else {
422+ var registeredComputation = result._zone.registerCallback (computation);
423+ result._zone.createTimer (duration, () {
420424 FutureOr <T > computationResult;
421425 try {
422- computationResult = computation ( );
426+ computationResult = result._zone. run (registeredComputation );
423427 } catch (e, s) {
424428 _completeWithErrorCallback (result, e, s);
425429 return ;
426430 }
427431 result._complete (computationResult);
428- }
429- });
432+ });
433+ }
430434 return result;
431435 }
432436
@@ -704,31 +708,63 @@ abstract interface class Future<T> {
704708 /// // Outputs: 'Finished with 3'
705709 /// ```
706710 static Future <void > doWhile (FutureOr <bool > action ()) {
707- _Future <void > doneSignal = new _Future <void >();
708- late void Function (bool ) nextIteration;
709- // Bind this callback explicitly so that each iteration isn't bound in the
710- // context of all the previous iterations' callbacks.
711- // This avoids, e.g., deeply nested stack traces from the stack trace
711+ var zone = Zone .current;
712+ _Future <void > doneSignal = _Future <void >.zone (zone);
713+
714+ /// As a function instead of a tear-off because some compilers
715+ /// prefer that. (Same overhead for creating, but tear-offs have
716+ /// more complicated equality, which isn't used anyway.)
717+ void completeError (Object e, StackTrace s) {
718+ doneSignal._completeError (e, s);
719+ }
720+
721+ // Bind/register the callbacks only once, and reuse them on every iteration.
722+ // This avoids, e.g., deeply nested stack traces from the `stack_trace`
712723 // package.
713- nextIteration = Zone .current.bindUnaryCallbackGuarded ((bool keepGoing) {
724+ void Function (bool )? registeredNextIteration;
725+ void Function (Object , StackTrace )? registeredCompleteError;
726+
727+ /// True until the first asynchronous gap.
728+ bool sync = true ;
729+ void nextIteration (bool keepGoing) {
714730 while (keepGoing) {
715731 FutureOr <bool > result;
716732 try {
717733 result = action ();
718734 } catch (error, stackTrace) {
719- // Cannot use _completeWithErrorCallback because it completes
720- // the future synchronously.
721- _asyncCompleteWithErrorCallback (doneSignal, error, stackTrace);
735+ if (sync ) {
736+ // Complete asynchronously if still running synchronously.
737+ _asyncCompleteWithErrorCallback (doneSignal, error, stackTrace);
738+ } else {
739+ _completeWithErrorCallback (doneSignal, error, stackTrace);
740+ }
722741 return ;
723742 }
724743 if (result is Future <bool >) {
725- result.then (nextIteration, onError: doneSignal._completeError);
744+ if (result is _Future <bool >) {
745+ var onValue =
746+ registeredNextIteration ?? = zone.registerUnaryCallback (
747+ nextIteration,
748+ );
749+ var onError =
750+ registeredCompleteError ?? = zone.registerBinaryCallback (
751+ completeError,
752+ );
753+ // Reuse registered callbacks when it's a `_Future`.
754+ result._addThenListener (zone, onValue, onError);
755+ } else {
756+ // Let `then` do callback registration for non-native futures.
757+ // It will do that anyway.
758+ result.then (nextIteration, onError: completeError);
759+ }
760+ sync = false ;
726761 return ;
727762 }
728763 keepGoing = result;
729764 }
730765 doneSignal._complete (null );
731- });
766+ }
767+
732768 nextIteration (true );
733769 return doneSignal;
734770 }
@@ -898,7 +934,7 @@ abstract interface class Future<T> {
898934
899935 /// Stop waiting for this future after [timeLimit] has passed.
900936 ///
901- /// Creates a new _timeout future_ that completes
937+ /// Creates a _timeout future_ that completes
902938 /// with the same result as this future, the _source future_,
903939 /// *if* the source future completes in time.
904940 ///
@@ -1159,7 +1195,7 @@ class TimeoutException implements Exception {
11591195/// one — you can use a Completer as follows:
11601196/// ```dart
11611197/// class AsyncOperation {
1162- /// final Completer _completer = new Completer();
1198+ /// final Completer _completer = Completer();
11631199///
11641200/// Future<T> doOperation() {
11651201/// _startOperation();
@@ -1198,7 +1234,7 @@ abstract interface class Completer<T> {
11981234 /// completer.complete('completion value');
11991235 /// }
12001236 /// ```
1201- factory Completer () => new _AsyncCompleter <T >() ;
1237+ factory Completer () = _AsyncCompleter <T >;
12021238
12031239 /// Completes the future synchronously.
12041240 ///
@@ -1249,7 +1285,7 @@ abstract interface class Completer<T> {
12491285 /// foo(); // In this case, foo() runs after bar().
12501286 /// });
12511287 /// ```
1252- factory Completer .sync () => new _SyncCompleter <T >() ;
1288+ factory Completer .sync () = _SyncCompleter <T >;
12531289
12541290 /// The future that is completed by this completer.
12551291 ///
@@ -1331,7 +1367,7 @@ abstract interface class Completer<T> {
13311367 bool get isCompleted;
13321368}
13331369
1334- // Helper function completing a _Future with error, but checking the zone
1370+ // Helper function completing a ` _Future` with error, but checking the zone
13351371// for error replacement and missing stack trace first.
13361372// Only used for errors that are *caught*.
13371373// A user provided error object should use `_interceptUserError` which
0 commit comments