Focus on
- The Dart code runs in an executed thread.
- Blocking thread execution of code can cause the program to freeze.
- The Future object (Futures) represents the result of asynchronous execution (the result of the execution or I/O operation to be completed).
- Asynchronous functions use await()(or then()) and pause execution until the future is complete.
- Asynchronous functions use try-cache expressions to catch errors.
- Build an ISOLATE (web worker), run the code immediately,
The Dart code runs in an executed thread. If Dart code blocks, for example, running a long operation or waiting for an I/O operation, the program will freeze. Asynchronous operations allow you to do other work while waiting for one operation to complete. Dart uses a Future object (Futures) to represent asynchronous execution results. You can use async and await or you can use the Future API for futures development.
Node: All Dart code runs within the ISOLATE context, which has all the memory for the Dart code. When Dart code is executing, no other code can be run within the ISOLATE. If you want to run multiple parts of the Dart code at the same time, you can run them on other ISOLates (Web workers instead of ISOLates). Multiple ISOLates run simultaneously, usually on their own CPU cores. The ISOLATE does not share memory and the only way they communicate with each other is by sending messages. For more information about ISOLATE, see the document Debilitating or Web workers
introduce
Let’s look at some code that can cause an application to freeze:
// Synchronous code
void printDailyNewsDigest() {
var newsDigest = gatherNewsReports(); // Can take a while.
print(newsDigest);
}
main() {
printDailyNewsDigest();
printWinningLotteryNumbers();
printWeatherForecast();
printBaseballScore();
}
Copy the code
Our program collects the news of the day and prints it, then prints some other items of interest to the user:
<gathered news goes here>
Winning lotto numbers: [23, 63, 87, 26, 2]
Tomorrow's forecast: 70F, sunny.
Baseball score: Red Sox 10, Yankees 0
Copy the code
Our code has a potential problem: Because gatherNewsReports() blocks, the rest of the code has to wait for gatherNewsReports() to read the return value from the file. If reading the file takes a long time, the user must wait, although the user might prefer to know if they won the lottery, what the weather will be tomorrow, and who won today’s game.
To ensure program responsiveness, Dart library authors handle time-consuming operations in asynchronous mode, and these functions use the Future as the return value.
What is #Future? A Future is a Future object that represents an asynchronous operation that produces a result of type T. If the result is an unavailable value, the return type is Future. When a function that returns futrue is called, two things happen:
- This function will join the work queue and return an unfinished Future object.
- Later, when the operation is complete, return the value of the completed Future object or an error.
There are two ways to use future:
- Use async and await
- In the Future the API
Async and await
Async and await are part of Dart’s support for asynchronous programming. They allow you to write asynchronous code that looks like synchronous code and doesn’t need to use the Future API. An asynchronous function can be preceded by the async keyword. The await keyword is used only in async functions. The following program uses async and await to simulate from www.dartlang.org. Read contents:
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
Future<void> printDailyNewsDigest() async {
var newsDigest = await gatherNewsReports();
print(newsDigest);
}
main() {
printDailyNewsDigest();
printWinningLotteryNumbers();
printWeatherForecast();
printBaseballScore();
}
printWinningLotteryNumbers() {
print('Winning lotto numbers: [23, 63, 87, 26, 2]');
}
printWeatherForecast() {
print("Tomorrow's forecast: 70F, sunny.");
}
printBaseballScore() {
print('Baseball score: Red Sox 10, Yankees 0');
}
const news = '<gathered news goes here>';
const oneSecond = Duration(seconds: 1);
// Imagine that this function is more complex and slow. :)
Future<String> gatherNewsReports() =>
Future.delayed(oneSecond, () => news);
// Alternatively, you can get news from a server using features
// from either dart:io or dart:html. For example:
//
// import 'dart:html';
//
// Future<String> gatherNewsReportsFromServer() => HttpRequest.getString(
// 'https://www.dartlang.org/f/dailyNewsDigest.txt'/ /);Copy the code
Running results:
Winning lotto numbers: [23, 63, 87, 26, 2]
Tomorrow's forecast: 70F, sunny.
Baseball score: Red Sox 10, Yankees 0
<gathered news goes here>
Copy the code
PrintDailyNewsDigest () is the first to be called, and although it only prints one line, the news is also the last to be printed. This is because the run and print code runs asynchronously.
In this example, printDailyNewsDigest() calls non-blocking gatherNewsReports(), which adds the execution task to the queue but does not prevent the rest of the code from executing. It prints lottery numbers and predicts baseball scores. When gatherNewsReports() is finished getting the news, print it. If gatherNewsReports() takes some time to complete, it will not have a significant impact on the user due to asynchronous execution. Users can read other news before printing the daily news.
Note that the return type of gatherNewsReports() is Future, which means that the return value is a Future character. PrintDailyNewsDigest () has no return value and its return type is Future.
The following figure shows the call flow, with numbers and steps corresponding to each other:
- Program running
- The main function calls printDailyNewsDigest(), and printDailyNewsDigest() starts executing.
- PrintDailyNewsDigest () calls atherNewsReports() with await, and atherNewsReports() begins execution.
- GatherNewsReports () returns an unfinished Future (one Future instance).
- Because printDailyNewsDigest() is an asynchronous function and waits for a return value, it pauses and returns an unfinished future (in this case, the future) to its caller (in this case, the main function).
- Execute the rest of the print function. Because they are synchronous, each function is completely executed before the next function is executed. Lottery numbers, for example, are printed in advance of weather forecasts.
- When main() completes execution, asynchronous functions can still execute. First gatherNewsReports() returns the Future, and then printDailyNewsDigest() continues to print the news.
- When the printDailyNewsDigest() body completes execution, the completed Future is returned and the program exits.
Notice that the asynchronous function starts executing immediately (synchronously). When the following condition first occurs, the function suspends execution and returns an unfinished future:
- The first await expression of a function (after the function obtains an unfinished future).
- Reture statements.
- The function body ends.
Error handling
Asynchronous functions use try-cache for error handling.
Future<void> printDailyNewsDigest() async {
try {
var newsDigest = await gatherNewsReports();
print(newsDigest); } catch (e) { // Handle error... }}Copy the code
Try-cache behaves the same in asynchronous and synchronous code; if the code in the try block throws an exception, the code in the catch clause executes.
The order processing
You can use multiple await expressions to ensure sequential execution, i.e. each statement is completed before the next statement is executed:
// Sequential processing using async and await.
main() async {
await expensiveA();
await expensiveB();
doSomethingWith(await expensiveC());
}
Copy the code
ExpensiveA () is executed only after the execution is complete.
Before adding async and await in Dart 1.9, you must use the Future API. It is still possible to see the Future API in older Dart code and in code that needs more functionality than asyn-await.
Write asynchronous code using the Future API and register callbacks with THEN (). When the Future completes, the callback is executed.
The following program uses the Future API to simulate from www.dartlang.org. Read contents:
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
Future<void> printDailyNewsDigest() {
final future = gatherNewsReports();
return future.then(print);
// You don't *have* to return the future here. // But if you don't, callers can't await it. } main() { printDailyNewsDigest(); printWinningLotteryNumbers(); printWeatherForecast(); printBaseballScore(); } printWinningLotteryNumbers() { print('Winning lotto numbers: [23, 63, 87, 26, 2]'); } printWeatherForecast() { print("Tomorrow's forecast: 70F, sunny."); } printBaseballScore() { print('Baseball score: Red Sox 10, Yankees 0'); } const news = '
'; const oneSecond = Duration(seconds: 1); // Imagine that this function is more complex and slow. :) Future
gatherNewsReports() => Future.delayed(oneSecond, () => news); // Alternatively, you can get news from a server using features // from either dart:io or dart:html. For example: // // import 'dart:html'; // // Future
gatherNewsReportsFromServer() => HttpRequest.getString( // 'https://www.dartlang.org/f/dailyNewsDigest.txt', // );
Copy the code
Result output:
Winning lotto numbers: [23, 63, 87, 26, 2]
Tomorrow's forecast: 70F, sunny.
Baseball score: Red Sox 10, Yankees 0
<gathered news goes here>
Copy the code
PrintDailyNewsDigest () is the first to be called, and although it only prints one line, the news is also the last to be printed. This is because the run and print code runs asynchronously.
Procedure execution steps:
- Start to perform
- The main() function calls printDailyNewsDigest(), which does not return immediately, but instead calls gatherNewsReports().
- GatherNewsReports () starts getting news and returns a Future.
- PrintDailyNewsDigest () uses THEN () to process the corresponding Future return value. Calling then() returns a new Future, which will be used as a callback argument to then().
- Execute the rest of the print function. Because they are synchronous, each function is completely executed before the next function is executed. Lottery numbers, for example, are printed in advance of weather forecasts.
- After all the news items have been received, gatherNewsReports() returns a Future containing the string of news information.
- Execute the then() specified in printDailyNewsDigest() to print the news.
- Exit the program.
Node: In printDailyNewsDigest(), future.then(print) is equivalent to: future.then((newsDigest) => print(newsDigest))
Alternatively, then() internal code can use {}:
Future<void> printDailyNewsDigest() {
final future = gatherNewsReports();
return future.then((newsDigest) {
print(newsDigest);
// Do something else...
});
}
Copy the code
You need to supply a callback to then(), even if the Future is of type Future. By convention, a useless parameter is represented by an underscore.
final future = printDailyNewsDigest();
return future.then((_) {
// Code that doesn't use the `_` parameter... print('All reports printed.');
});
Copy the code
Using the Future API, you can catch errors using catchError().
Future<void> printDailyNewsDigest() =>
gatherNewsReports().then(print).catchError(handleError);
Copy the code
If the news data read is invalid, the code is executed as follows:
- GatherNewsReports () returns the Future with error information.
- The future returned by then() ends with an error, and print() is not used.
- CatchError () (handleError()) handles errors, catchError() returns a normal future, and the error is not propagated.
Chained pattern is a common pattern for Future apis. The Future API can be equated to the try-catch module.
Like then(), catchError() returns a new Future, which is the return value of the callback. For more details and examples, see Futures and Error Handling.
Calling multiple functions
Consider three functions, expensiveA(), expensiveB(), and expensiveC(), all of which return a Future object. You can call them sequentially, or you can start them at the same time and do something after all the functions have been executed. The Future interface can handle both use cases easily.
Chain calls are made using then()
When functions need to be executed sequentially, use chained then():
expensiveA()
.then((aValue) => expensiveB())
.then((bValue) => expensiveC())
.then((cValue) => doSomethingWith(cValue));
Copy the code
Nested callbacks work, but are difficult to read.
Use future.wait () to wait for multiple futures to complete
If the order in which the function is executed is not important, you can use future.wait ().
When you pass a future list to future.wait (), it immediately returns an incomplete future. The future is not completed until a given list of futures has been executed. The return value of the future, which consists of the return value of each future in the list.
Future.wait([expensiveA(), expensiveB(), expensiveC()])
.then((List responses) => chooseBestResponse(responses, moreInfo))
.catchError(handleError);
Copy the code
If either function returns an error, futrue of future.wait () ends with an error. Use catchError() to handle errors.
Read the following documentation for more details on using future and asynchronous programming in Dart:
- Futures and Error Handling
- The Event Loop and Dart
- Asynchrony support
- Web Workers and web futures.
Asynchronous Programming: Futures