Understanding Futures in Flutter and Dart

Meysam Mahfouzi
3 min readApr 10, 2019

The concept of Future data type is very easy to understand. Although the official documentation has explained this concept very well, in this article I will try to explain it in my own words, which will hopefully help you get your head around it, if you have not already.

When a function returns a Future, it means that it takes a while for its result to be ready, and the result will be available in the future.

The most famous example of a function that may take some time to return the result is http.get(url) which is usually used to call RESTFul API, where we have to send an HTTP request and wait for the response. In the following example, http.get() method returns a Future object:

Calling a function that returns a Future, will not block your code, that’s why that function is called asynchronous. Instead, it will immediately return a Future object, which is at first uncompleted.

Future<T> means that the result of the asynchronous operation will be of type T. For example, if a function returns Future<String>, this means that in the future, it will provide a string to you.

For the sake of practicing, we can use one of the Future constructors to create our own Future object. The following code creates an instance of Future<String> which will complete immediately. Note how we have provided an anonymous function as the parameter of the Future’s constructor. The return value of this anonymous function determines the type of the instantiated future object. Here “Latest News” is of type String, therefore an instance ofFuture<String>will be created.

To simulate a Future that completes after some time, we can use the Future.delayed constructor. The future object in the following example will complete after two seconds:

The result of the Future is available only when the Future is completed.

You can access the result of the Future using either of the following keywords:

  • then
  • await

Suppose that the getNews function returns an instance of Future<String>.

You can consume the result of this function in either of the following ways:


Note that the await keyword can only be used in the body of an async function:

The result of an async function must be a Future.

Tip: If a function returns a Future, it’s considered asyncrounous; you do not need to mark the body of this function with async keyword. The async keyword is necessary only if you have used the await keyword in the body of your function.

If your asynchronous function does not return anything (for example if it only prints something), the return type of function should be Future<void>.

The then keyword returns a Future<T> as well, it means that you can chain them:

The type of Future<T> returned by then keyword is determined by the return value of the function defined in the body of then.

Calling then() returns a new Future that will complete with the value returned by then()’s callback.

The following code is a real-world example. In this piece of code, I have used the permission_handler package to check if the application has permission to access the phone contacts. The checkPermissionStatus function returns a future object.

Checking permissions with then:

checking permissions using await:

The purpose of this article was to summarize the well written official documentation: https://www.dartlang.org/tutorials/language/futures

I would suggest you watch the following tutorial as well:

I tried to keep this article as concise as possible. One thing I didn’t talk about is how to handle errors while working with Future objects. If you are using the Future API (“then” keyword), you will be able to catch errors using catchError() function, otherwise if you are using the “await” keyword, simply use try-catch blocks to handle the errors.

Thanks for reading :)