An asynchronous operation executes in a thread, separate from the main application thread. When an application calls a method to perform an operation asynchronously, the application can continue executing while the asynchronous method performs its task.
Let’s take an example to understand this concept. Here, the program accepts user input using the IO library.
import 'dart:io'; void main() { print("Enter your name :"); // prompt for user input String name = stdin.readLineSync(); // this is a synchronous method that reads user input print("Hello Mr. ${name}"); print("End of main"); }
The readLineSync() is a synchronous method. This means that the execution of all instructions that follow the readLineSync() function call will be blocked till the readLineSync() method finishes execution.
The stdin.readLineSync waits for input. It stops in its tracks and does not execute any further until it receives the user’s input.
The above example will result in the following output −
Enter your name : Tom // reads user input Hello Mr. Tom End of main
In computing, we say something is synchronous when it waits for an event to happen before continuing. A disadvantage in this approach is that if a part of the code takes too long to execute, the subsequent blocks, though unrelated, will be blocked from executing. Consider a webserver that must respond to multiple requests for a resource.
A synchronous execution model will block every other user’s request till it finishes processing the current request. In such a case, like that of a web server, every request must be independent of the others. This means, the webserver should not wait for the current request to finish executing before it responds to request from other users.
Simply put, it should accept requests from new users before necessarily completing the requests of previous users. This is termed as asynchronous. Asynchronous programming basically means no waiting or non-blocking programming model. The dart:async package facilitates implementing asynchronous programming blocks in a Dart script.
The following example better illustrates the functioning of an asynchronous block.
Step 1 − Create a contact.txt file as given below and save it in the data folder in the current project.
1, Tom 2, John 3, Tim 4, Jane
Step 2 − Write a program which will read the file without blocking other parts of the application.
import "dart:async"; import "dart:io"; void main(){ File file = new File( Directory.current.path+"\\data\\contact.txt"); Future<String> f = file.readAsString(); // returns a futrue, this is Async method f.then((data)=>print(data)); // once file is read , call back method is invoked print("End of main"); // this get printed first, showing fileReading is non blocking or async }
The output of this program will be as follows −
End of main 1, Tom 2, John 3, Tim 4, Jan
The "end of main" executes first while the script continues reading the file. The Future class, part of dart:async, is used for getting the result of a computation after an asynchronous task has completed. This Future value is then used to do something after the computation finishes.
Once the read operation is completed, the execution control is transferred within "then()". This is because the reading operation can take more time and so it doesn’t want to block other part of program.
The Dart community defines a Future as "a means for getting a value sometime in the future." Simply put, Future objects are a mechanism to represent values returned by an expression whose execution will complete at a later point in time. Several of Dart’s built-in classes return a Future when an asynchronous method is called.
Dart is a single-threaded programming language. If any code blocks the thread of execution (for example, by waiting for a time-consuming operation or blocking on I/O), the program effectively freezes.
Asynchronous operations let your program run without getting blocked. Dart uses Future objects to represent asynchronous operations.