Olson CloudWorks πŸš€

Whats the difference between async and async in Dart

September 19, 2026

πŸ“‚ Categories: Dart
🏷 Tags: Flutter
Whats the difference between async and async in Dart

Dart, a versatile and powerful programming language, provides developers with robust tools for handling asynchronous operations. Two keywords that frequently surface in this context are async and async. While both are designed to manage asynchronous code, they operate in fundamentally different ways and serve distinct purposes. Understanding the difference between async and async is crucial for writing efficient, non-blocking Dart applications. This article dives deep into exploring their nuances, providing clear explanations, real-world examples, and practical guidelines to help you master asynchronous programming in Dart. We’ll cover how each keyword affects the execution flow, the types of values they return, and the scenarios where each is most appropriate, ensuring you can make informed decisions when designing your Dart applications.

Understanding async in Dart

The async keyword in Dart marks a function as asynchronous, enabling it to perform non-blocking operations. When you declare a function as async, Dart automatically wraps its return value in a Future. A Future represents a value that might not be available immediately but will be provided sometime in the future. This allows the program to continue executing other tasks without waiting for the asynchronous operation to complete. Inside an async function, you can use the await keyword to pause execution until a Future completes, making asynchronous code look and behave more like synchronous code.

Consider a scenario where you need to fetch data from a remote server. Without async and await, you would have to deal with callbacks or chained Future operations, which can quickly become complex and difficult to read. By using async, you can write code that looks synchronous but executes asynchronously, improving both readability and maintainability. For example, you might use async to handle user input, network requests, or file system operations, ensuring your application remains responsive even when performing time-consuming tasks.

Here’s a simple example:

dart Future fetchData() async { await Future.delayed(Duration(seconds: 2)); // Simulate network delay return ‘Data fetched!’; } void main() async { print(‘Fetching data…’); String data = await fetchData(); print(data); // Output: Data fetched! print(‘Done!’); } In this example, fetchData is an async function that simulates fetching data from a server. The await keyword pauses execution until the simulated network delay is complete, and then the function returns the fetched data. The main function also uses async to await the result of fetchData, ensuring that the “Data fetched!” message is printed only after the data is actually available. This clean, linear structure is a key benefit of using async in Dart.

Exploring async in Dart

While async deals with single asynchronous results wrapped in a Future, async introduces a different concept: asynchronous streams. A function marked with async returns a Stream, which represents a sequence of asynchronous events. This is particularly useful when you need to handle a series of data points over time, such as reading data from a large file, receiving real-time updates from a server, or processing a continuous stream of sensor data.

Inside an async function, you use the yield keyword to emit values into the Stream. Each yield statement effectively pauses the function, sends the value to the stream, and then resumes execution from where it left off. This allows you to generate a sequence of values asynchronously without blocking the main thread. The consumer of the Stream can then listen for these values and process them as they become available.

Consider the following example:

dart Stream countStream(int to) async { for (int i = 1; i <= to; i++) { await Future.delayed(Duration(milliseconds: 500)); // Simulate delay yield i; } } void main() { countStream(5).listen((number) { print(‘Received: $number’); }); print(‘Stream started’); } In this example, countStream is an async function that generates a stream of integers from 1 to a specified limit. The yield keyword emits each number into the stream, with a small delay to simulate an asynchronous operation. The main function then listens to the stream and prints each received number. The output will show “Stream started” immediately, followed by the numbers 1 through 5 being printed with a half-second delay between each, demonstrating the asynchronous nature of the stream.

Key Differences: async vs. async

The primary difference between async and async lies in the type of asynchronous data they handle and the return values they produce. async functions return a single Future that represents a single asynchronous result, while async functions return a Stream that represents a sequence of asynchronous events. Understanding this distinction is crucial for choosing the right tool for the job.

Here’s a summary of the key differences:

  • Return Type: async returns a Future; async returns a Stream.
  • Data Handling: async handles single asynchronous values; async handles sequences of asynchronous values.
  • Keywords: async uses await to pause execution; async uses yield to emit values.
  • Use Cases: async is suitable for single asynchronous operations like fetching data or performing a computation; async is ideal for handling continuous streams of data, such as reading from a file or receiving real-time updates.

To further clarify, consider these scenarios:

  • Use async when you need to perform a single asynchronous task and obtain a single result. For example, authenticating a user or retrieving a configuration file.
  • Use async when you need to process a sequence of asynchronous events or generate a stream of data. For example, reading a large CSV file line by line or receiving real-time stock market data.

Choosing between async and async depends entirely on the nature of the asynchronous operation you are performing. Selecting the appropriate keyword ensures your code is efficient, readable, and maintainable.

Practical Examples and Use Cases

To illustrate the practical applications of async and async, let’s examine some real-world examples.

Example 1: Using async to Fetch Data

Imagine you’re building a weather application that needs to fetch weather data from an API. You would use an async function to perform the network request and retrieve the data. Here’s how you might implement this:

dart import ‘dart:convert’; import ‘package:http/http.dart’ as http; Future> fetchWeather(String city) async { final apiKey = ‘YOUR_API_KEY’; // Replace with your actual API key final url = Uri.parse(‘https://api.openweathermap.org/data/2.5/weather?q=$city&amp;appid=$apiKey&amp;units=metric'); final response = await http.get(url); if (response.statusCode == 200) { return jsonDecode(response.body); } else { throw Exception(‘Failed to fetch weather data’); } } void main() async { try { final weatherData = await fetchWeather(‘London’); print(‘Temperature in London: ${weatherData[‘main’][’temp’]}Β°C’); } catch (e) { print(‘Error: $e’); } } In this example, fetchWeather is an async function that fetches weather data from the OpenWeatherMap API. The await keyword pauses execution until the HTTP request completes, and then the function returns the parsed JSON data. This is a classic use case for async, where you need to perform a single asynchronous operation and obtain a single result. You can learn more about the OpenWeatherMap API here.

Example 2: Using async to Read a Large File

Consider a scenario where you need to process a large log file, reading it line by line. Using async allows you to process the file asynchronously without loading the entire file into memory. This approach is more efficient for handling large datasets. The following featured snippet-optimized paragraph explains how to read a large file using async.

To efficiently read a large file line by line in Dart, use an async function that returns a Stream<string></string>. Within the function, open the file and use a BufferedReader to read each line asynchronously. Employ the yield keyword to emit each line into the stream as it’s read, allowing the consumer to process the data incrementally without loading the entire file into memory at once. This method ensures optimal performance and resource utilization when dealing with substantial text files. See Dart’s documentation on File class for more details.

dart import ‘dart:io’; Stream readFileByLines(String filePath) async { final file = File(filePath); final lines = file.readAsLines().asStream(); // Read the entire file and convert the lines to a stream await for (final line in lines) { yield line; } } void main() async { final filePath = ‘path/to/your/large_file.txt’; // Replace with your file path readFileByLines(filePath).listen((line) { print(‘Line: $line’); }); } In this example, readFileByLines is an async function that reads a file line by line and emits each line as a value in the stream. The await for loop iterates through the lines asynchronously, and the yield keyword emits each line into the stream. This allows you to process the file incrementally without loading the entire file into memory. Make sure to replace ‘path/to/your/large_file.txt’ with the actual path to your file.

Infographic here
FAQ: async and async in Dart ----------------------------
**Q: When should I use async instead of async?**
A: Use `async` when you need to perform a single asynchronous operation and obtain a single result, such as fetching data from an API or performing a calculation. It's suitable for scenarios where you're waiting for a single event to complete.
**Q: What is the purpose of the yield keyword in async functions?**
A: The `yield` keyword is used in `async` functions to emit values into the stream. Each `yield` statement pauses the function, sends the value to the stream, and then resumes execution from where it left off. It allows you to generate a sequence of values asynchronously.
**Q: Can I use await inside an async function?**
A: Yes, you can use `await` inside an `async` function. This allows you to perform asynchronous operations while generating the stream of values. For example, you might `await` the result of a network request before emitting a value into the stream.
**Q: How do I handle errors in async and async functions?**
A: In `async` functions, you can use `try-catch` blocks to handle exceptions that occur during asynchronous operations. In `async` functions, you can also use `try-catch` blocks to handle exceptions and emit error events into the stream using `yield Stream.fromFuture(Future.error(e))` or similar techniques. It's important to handle errors gracefully to prevent your application from crashing. You can find more on error handling from [Effective Dart documentation](https://dart.dev/guides/language/effective-dart/designdo-handle-errors-gracefully).
**Q: What are the benefits of using streams?**
A: Streams provide a way to handle asynchronous data in a sequential manner. They are particularly useful for processing continuous streams of data, such as real-time updates from a server or reading large files. Streams also allow you to apply transformations and filters to the data as it flows through the stream, making them a powerful **Question & Answer :** I am making an application using flutter framework . During this I came across with the keywords in Dart `async` and `async*`. Can anybody tell me what's the difference between them?

Short answer

  • async gives you a Future
  • async* gives you a Stream.

async

You add the async keyword to a function that does some work that might take a long time. It returns the result wrapped in a Future.

Future<int> doSomeLongTask() async { await Future.delayed(const Duration(seconds: 1)); return 42; } 

You can get that result by awaiting the Future:

main() async { int result = await doSomeLongTask(); print(result); // prints '42' after waiting 1 second } 

async*

You add the async* keyword to make a function that returns a bunch of future values one at a time. The results are wrapped in a Stream.

Stream<int> countForOneMinute() async* { for (int i = 1; i <= 60; i++) { await Future.delayed(const Duration(seconds: 1)); yield i; } } 

The technical term for this is asynchronous generator function. You use yield to return a value instead of return because you aren’t leaving the function.

You can use await for to wait for each value emitted by the Stream.

main() async { await for (int i in countForOneMinute()) { print(i); // prints 1 to 60, one integer per second } } 

Going on

Watch these videos to learn more, especially the one on Generators: