Well, no. Dart has a single thread, or event-loop, of execution. However, commonly you’ll see a code using Future have a comment something to the effect of “// Avoid race conditions: Check for …”. What does that mean?
New to futures? Read asynchronous programming: Futures on the Dart site.
While Dart has a single thread of execution, it can interact with other code (Dart or otherwise, such as server-side) that runs in a separate thread. What Future<T> as an API means is simply “get a value, T, at a future point in time”. That time? It could be at the end of the microtask loop, it could be after a second, after a file is read from disk, after an RPC completes. It could also be never (due to a timeout, for example).
You can review all of the examples in this blog post on GitHub.
Let’s introduce a simple example:
We print the string “1”, “2”, “3”, and “4” — seemingly in order, but in reality it will print “1”, “4”, “2”, and “3”. That’s because “1” is printed synchronously, while “2” is printed at the end of the microtask loop, and “3” is printed a future event loop.
You can also use the Completer API to adapt a non-Future API:
Dart is able to spawn standalone processes, called Isolates (web workers in dart2js), which do not share memory when the main program, but are able to asynchronously, in another process (effectively a thread of sorts) is able to do computations without blocking the main thread.
In the below example we compute the fibonacci sequence twice — once synchronously in the same thread — and once asynchronously in another isolate.
In this example, Future is still used — it just means “will execute in the future”, remember? In this case, we spawn another isolate, ask it to compute, and the future completes when we have a result. If, for example, your computer was under heavy load it could take a little while.
Seem confusing? The isolate API is fairly low-level. When using in your own code I’d recommend looking at package:isolate or the IsolateChannel class from package:stream_channel.
How about another example, this time file I/O. We can simulate the difference between File#readAsStringSync and File#readAsString ourselves using an Isolate:
In this case we read “file.json” three times — once synchronously, once asynchronously (i.e. in another thread managed by the Dart VM), and finally once more synchronously, but in another isolate.
Since Dart 1.22.0, we’ve introduced a limited union type, FutureOr<T> — which represents either Future<T> or T. It’s valid in the type system to have either. As an example, take a look at caching the result of a future:
I hope you enjoyed this short blog post, and if you have any questions about using futures or the asynchronous API in Dart leave a comment here or on twitter. Thanks!
Hacker Noon is how hackers start their afternoons. We’re a part of the @AMIfamily. We are now accepting submissions and happy to discuss advertising & sponsorship opportunities.
To learn more, read our about page, like/message us on Facebook, or simply, tweet/DM @HackerNoon.
If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!