Dart Concurrency: Asynchronous programming

Dart Concurrency: Asynchronous programming

Asynchronous programming in Dart involves executing tasks concurrently, without waiting for each task to finish before starting the next one. This is useful for tasks like fetching data from a server, where waiting for a response would block the program's execution. Instead, you can initiate the operation and continue with other tasks.

1. Futures

In Dart, a Future represents a value or error that will be available at some point in the future.

Futures are used to perform asynchronous operations, such as fetching data from a network, reading files, or executing time-consuming computations.

Instead of waiting for the operation to complete synchronously, Futures allow your program to continue executing other tasks while waiting for the result.

For example, if you have a time-consuming task, like fetching data from the internet, you can use a Future to handle it. The Future says, "I'm working on getting the data, and once it's ready, I'll let you know."

Here's a Let's understand with one example:

Imagine you order food at a restaurant. The waiter gives you a token (the Future), and tells you, "Your food will be ready soon. Hold on to this token. When it's ready, we'll bring it to you." You can continue doing other things while waiting for your food. When the food is ready, the waiter fulfills the promise by bringing you the meal.

This snippet shows how we order food asynchronously. We initiate the order, proceed with other tasks, and handle the delivered result when the Future is fulfilled.

Future<String> fetchFood() {
  return Future.delayed(Duration(seconds: 5), () {
    return "Delicious meal"; // Simulating fetching data after 2 seconds
  });
}

void main() {
  print("Ordering food...");
  Future<String> foodFuture = fetchFood();

  print("Doing something else while waiting...");

  foodFuture.then((food) {
    print("Got the food: $food");
  });
}

Here ,we can see that when we run our program at that time we get print of first two statement and the last statement will run after 5 second, because we have used delayed in this.

This output will print after 5 second.


Async, Await, Future Keywords

Async:

Think of it as saying, "I'm going to do something that takes time, but I won't stop everything else." So, you're telling Dart, "While the bread is toasting, I can do other tasks."

Await:

It's like pausing to check if something is ready. In our sandwich example, it's like saying, "Wait until the bread is done toasting before moving on."

Future:

This is Dart's way of promising something. It's like telling Dart, "I'm working on getting something for you, and when it's ready, I'll let you know."

Let's Understand with one Example :

// Async function that returns a Future
Future<String> makeSandwich() async {
  print("Putting bread in toaster...");

  // Simulating toasting time
  await Future.delayed(Duration(seconds: 3));

  print("Toasted bread is ready!");
  return "Delicious sandwich";
}

void main() async {
  print("Starting sandwich making process...");

  // Await the Future to get the result
  String sandwich = await makeSandwich();

  print("Made a sandwich: $sandwich");
  print("Lunchtime is a success!");
}

Output:


Dart Futures: Creating Future from Scratch

Understanding Dart Futures: In Dart, a Future represents a value or error that will be available at some point in the future. Futures encapsulate asynchronous operations, allowing developers to write non-blocking code that performs tasks such as network requests, file I/O operations, or computational tasks asynchronously.

Creating Futures:

Creating a Future from scratch in Dart is straightforward. You can utilize the Future class constructor to define an asynchronous operation. Let's look at a simple example:

Future<String> fetchData() {
  return Future<String>(() {
    // Simulate a time-consuming operation
    return 'Fetched data!';
  });
}

In this example, the fetchData() function returns a Future that eventually resolves to the string 'Fetched data!'. The asynchronous operation is represented by a closure passed to the Future constructor.

Handling Futures:

Once you've created a Future, you can handle its completion using methods like .then() and .catchError(). The .then() method allows you to register a callback function to be invoked when the Future completes successfully, while .catchError() handles any errors that occur during its execution.

fetchData().then((value) {
  print('Data fetched: $value');
}).catchError((error) {
  print('Error fetching data: $error');
});

In this snippet, we use .then() to print the fetched data when the Future completes successfully, and .catchError() to handle any errors that may occur during its execution.