Concurrency in Dart — Part II
async, future, await and completer in dart.

Future
Dart has a type Future which is a promise to return a value of a certain type later.
Future<int> countTheStars();
Future itself is generic and can provide any type. If you call this function then it will immediately return a Future<int>. This future can be listened to or waited upon. In the background, it will call ISRO/NASA HTTP APIs (If any of these are available) and returns several stars or error (due to some issue). Assuming that you were listening to the future and therefore the result will be passed to you then.
Once the star counting machine returns from NASA/ISRO then it comes to Dart and tells it to put it back on the event queue. As we know event loop process the tasks in the event queue and eventually Future who was listening to the result will be notified once the results are picked from the event queue.
Future can be in any of these states
- Uncompleted.
- Completed with a value.
- Completed with an error.
Ex:
final myFuture = Future<int>.delayed(
Duration(milliseconds:1),
() => 42,
);
Future.delayed is a function that returns a future. It accepts a Duration object and a function that returns a value (based on future type, here is int). Dart runs this function after the duration mentioned by the Duration object.
Getting value from a Future
If you try to print myFuture then you will get this result:
print(myFuture)
Result:
Instance of 'Future<int>'
Getting results with callback
There are three callbacks: then, catchError and whenComplete.
Output
After the future
32
Future completed
If you read the last article then you would know why this is the order of print statements. print() is a synchronous function and Future.delayed is an asynchronous function.
The interesting thing to note here is that even if the duration was 0 milliseconds then also future code would have been pushed to the event queue and synchronous code would run first.
Getting the result with async-await
Callbacks are pretty easy to understand but they can be hard to read and implement. Our mind thinks better sequentially I believe. Also if you nest them then it is even more difficult. Just search callback hell in google once you will get the answers.
await works as syntactic sugar on top of then & catchError. Here the whole async function gets to be treated like a Future. Any function which uses await has to be an async function. When the called future function on which you are waiting is completed then it tells dart to put it back on the event queue and then it is picked like earlier. This happens for each awaits invocation. Using try-catch you see how you can catch errors as well as get to know when the future is completed.
Here as the await makes the flow synchronous logically, “after the future” is printed only after the future is completed.
Output
32
future is complete
after the future
Completer
Ok, now you understand Future & async-await. Now you are using an HTTP library for the rest APIs which is purely based on callbacks(non Future dart API) and you want to use present a Dart facade to your consumers. In this case, Completer comes to the rescue.
In line number 4 we create a Completer that returns a String when it completes. Completer has a future property which has a type of Future and you can normally use different ways as discussed above to get a value from it. If you see getHttpData receives two anonymous functions: onComplete and onError. In those anonymous functions, we can use our completer instance to complete it and the listener to the future will either receives the value or error based on the results from the HTTP library.
Further readings: