17
Future readData() {
    var completer = new Completer();
    print("querying");
    pool.query('select p.id, p.name, p.age, t.name, t.species '
        'from people p '
        'left join pets t on t.owner_id = p.id').then((result) {
      print("got results");
      for (var row in result) {
        if (row[3] == null) {
          print("ID: ${row[0]}, Name: ${row[1]}, Age: ${row[2]}, No Pets");
        } else {
          print("ID: ${row[0]}, Name: ${row[1]}, Age: ${row[2]}, Pet Name: ${row[3]},     Pet Species ${row[4]}");
        }
      }
      completer.complete(null);
    });
    return completer.future;
  }

The above is an example code taken from github SQLJocky Connector

I would like someone to explain me if possible why is the function which has a completer object created outside the pool.query is then calling a function completer.complete(null).

In short I am not able to understand the part after print executes.

Note:Kindly if possible I would also like to know how is future and Completer used for practical purpose both for DB and non DB operations.

I have explored the following links: Google groups discussion on Future and Completer

and the api reference documentation which is as given below Completer api reference and Future api Reference

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
IBRIT
  • 385
  • 1
  • 3
  • 13

3 Answers3

32

The Future object that is returned by that method is, in a sense, connected to that completer object, which will complete at some point "in the future". The .complete() method is called on the Completer, which signals the future that it is complete. Here's a more simplified example:

Future<String> someFutureResult(){
   final c = new Completer();
   // complete will be called in 3 seconds by the timer.
   new Timer(3000, (_) => c.complete("you should see me second"));
   return c.future;
}

main(){
   someFutureResult().then((String result) => print('$result'));
   print("you should see me first");
}

Here's a link to a blog post which details other scenarios where futures are helpful

Alexandre Ardhuin
  • 71,959
  • 15
  • 151
  • 132
John Evans
  • 6,858
  • 4
  • 28
  • 26
  • 1
    Thanks, the blog post does explain in detail.In short what I have realised is that it is very useful if we want to create ladder of events which are dependent on one another for results if I am not wrong. – IBRIT Dec 05 '12 at 21:39
  • Changing "ladder of events" to "sequence of asynchronous events" and I think you are right on target. :) – John Evans Dec 06 '12 at 14:12
  • The code, even after updating the syntax, is not working properly. It never gets to printing "you should see me second". – Igor F. Jun 02 '17 at 01:18
  • Correction to my comment above: It works, when run as a normal application. Earlier I ran it as a test and it didn't reach the "second". – Igor F. Jun 02 '17 at 06:46
  • 4
    @JohnEvans the blog post page link is broken. – Michel Feinstein Jun 05 '20 at 06:29
  • 1
    if you aim to return some custom type, set it in diamond brackets `Completer completer = Completer();` – Kirill Karmazin Jan 28 '21 at 19:21
6

Correct answer has errors in DartPad, the reason could be Dart version.

error : The argument type 'int' can't be assigned to the parameter type 'Duration'.
error : The argument type '(dynamic) → void' can't be assigned to the parameter type '() → void'.

The following snippet is complement

import 'dart:async';

Future<dynamic> someFutureResult(){
   final c = new Completer();
   // complete will be called in 3 seconds by the timer.
   new Timer(Duration(seconds: 3), () {     
       print("Yeah, this line is printed after 3 seconds");
       c.complete("you should see me final");       
   });
   return c.future;

}

main(){
   someFutureResult().then((dynamic result) => print('$result'));
   print("you should see me first");
}

reslut

you should see me first
Yeah, this line is printed after 3 seconds
you should see me final
chunhunghan
  • 51,087
  • 5
  • 102
  • 120
3

The Completer is used to provide a value to a future and signal it to fire any remaining callbacks and continuations that are attached to the future (i.e. at the call-site / in user code).

The completer.complete(null) is what's used to signal to the future that the async operation has completed. The API for complete shows that it must supply 1 argument (i.e. not optional).

void complete(T value)

This code is not interested in returning a value, just notifying the call-site that the operation is complete. As it just prints, you will need to check the console for the output.

mythz
  • 141,670
  • 29
  • 246
  • 390