0
votes

The following example is somewhat contrived but I'm trying understand the relationship between a Completer and the future generated by an await.

In the example below the 'doCalc' method contains an 'await' call and a Completer.

Its my understanding that when dart hits the 'await' statement that it immediately stops executing the method and returns a future.

If you run the code in dartpad you can see this in the output. The value = Instance of '_Future<int>' line is printed immediately.

This matches my expectation (i.e. await cause the method to return immediately). You can see from the 'value=' line that doCalc has returned a Future<int>.

This is also as expected.

The problem I'm having is that the last line of doCalc also returns a future. In this case the future generated by the completer.

As such it appears that doCalc returns TWO different futures.

1) The first one dart implicitly returns when await is called.

2) The second one I explicitly return via the return statement.

Given that the value of 'res' must contain the first future (as we print its value before the completer's future is returned) how is it that the line res.then waits until the second future completes.

There appears to be some magic here but I can't find any documentation on it.

Dart pad link:

https://dartpad.dev/a42cce3edf01b222206a627e8c8106af

import 'dart:async';
void main() {

  print('hi');
  var res = doCalc();
  print('value = ${res}');

  res.then((result) => print('result = $result'));
}

Future<int> doCalc() async
{
  var done = Completer<int>();

  await Future.delayed(Duration(seconds: 4), 
                 () { 
                   done.complete(10);

                     });

  return done.future;
}

1

1 Answers

0
votes

An async function returns a future that it creates itself. It does so "immediately", which means that it executes the body until the first asynchronous delay (await or await for) before the future is returned.

Any return statement inside an async function is used to complete the returned future. If your async function returns a Future<int>, then your return statements must return either an int or a Future<int>. In the former case, the returned future is completed with that integer. In the latter case, the returned future will complete with the same result as the return-future (let's name it that) when the return-future completes.

It is as if a return expression; in an async function is effectively a return await expression;. In this example, the line:

return done.future;

can be read as

return await done.future;

and that should explain the behavior you see.