A simple “crawler” thing was recently written with Flutter, which is to constantly request some interface and then read data. Before, I just tried Future with simple await and async, but later, I found that the simple way did not work, so I went to learn other uses of Future, and I learned all the uses of Future. Here is a note.
Lol, don’t ask me why I didn’t use Python… I happened to be using a computer that didn’t have an environment and wasn’t familiar with the Python API, so I came up with an idea that I could do anything with Flutter. Maybe I could use Flutter to create a visual interface later.
Dart message loop mechanism
Recommended article: Dart and message loops
Here’s a quick look at the Dart event loop, and for more details, see the recommended article.
Dart also has a message loop mechanism similar to Android’s Handler/Looper mechanism.
- A Dart application has a message loop and two queues, an Event queue and a MicroTask queue.
- Priority issue: The MicroTask queue has the highest priority, and the event queue is read for execution only after all microTask queues have finished executing.
- Events in the MicroTask queue,
- The event queue contains all foreign events: I/O, Mouse Events, Drawing Events, timers, messages between isolate, etc.
- Generally, events created by futures belong to the Event queue (with the exception of the Future.microtask method), so when a Future is created, it is inserted into the event queue and executed sequentially.
The introduction of the Future
In the process of writing a program, there is bound to be some time-consuming code that needs to be executed asynchronously. For network operations, we need to request data asynchronously, and we need to handle both successful and failed requests.
In Flutter, a Future is used to perform time-consuming operations indicating that a value will be returned in the Future, and a callback can be registered to listen for Future processing results using the THEN () method and catchError ().
See below for an explanation of the Future in the source code and a simple example. The then () and catchError () methods also return a Future object, so they can be written as chained calls.
An object representing a delayed computation.
Future<int> future = getFuture();
future.then((value) => handleValue(value))
.catchError((error) => handleError(error));
Copy the code
The state of the Flutter
A Future object can have two states
- Pending: Indicates that the Future object is still being evaluated and no result is available.
- Completed: Indicates that the Future object has been evaluated. There are two possible outcomes: a correct outcome and a failed outcome.
To create the Future
Note: First, the Future is a generic class and can be typed. If no type is specified, Future is returned by default.
Future createFuture()async{
return 1;
}
var future=createFuture();
print(future.runtimeType); . // Future<dynamic>Copy the code
A Future is commonly created in the following ways.
Basic usage
factory Future(FutureOr computation())
Future constructor to create a basic Future
var future = Future(() {
print("Ha ha ha.");
});
print("111"); //111 // hahahaCopy the code
You’ll notice that the printed “hahaha” string is printed later because the default Future is executed asynchronously. If you use the following code, and prefix the future with the await keyword, the “hahaha” string will be printed first. Await will wait until the future is finished before continuing to execute the following code.
This is related to the event loop above, as explained by the forwarding guru: The common code in the main method is executed synchronously, so it must be printed out first. After the main method is finished, the system will start to check whether there are any tasks in the MicroTask. If so, it will be executed, and continue to check the MicroTask until the microtask queue is empty. So the next print should be a microTask print. Finally, the Event queue is executed.
var future = await Future(() {
print("Ha ha ha.");
});
print("111"); // hahaha //111Copy the code
Future.value()
Creates a Future that returns the specified value
var future=Future.value(1);
print(future);
//Instance of 'Future<int>'
Copy the code
The Future of ()
Create a future that is deferred. For example, in the following example, a string can be printed after a Future delay of two seconds.
var futureDelayed = Future.delayed(Duration(seconds: 2), () {
print("Future.delayed");
return 2;
});
Copy the code
Advanced usage
Future.foreach(Iterable elements, FutureOr action(T element))
Based on a collection, a series of futures are created and executed in sequence. For example, in the following example, {1,2,3} creates three futures with a delay corresponding to the number of seconds. The result is that 1 is printed after 1 second, 2 seconds after 2 seconds, and 3 seconds after 3 seconds. The total time is 6 seconds.
Future. ForEach ({1, 2, 3}, {(num)return Future.delayed(Duration(seconds: num),(){print(num); }); });Copy the code
Future.wait ( Iterable<Future> futures,{bool eagerError: false, void cleanUp(T successValue)})
Used to wait for multiple futures to complete and collect their results. There are two possible outcomes:
- If all futures return normal results: the return result of the future is the set of results for all specified futures
- If one future returns an error: the future returns the value of the first error.
For example, in the following example, a Future is also created with three delays for each second. The result is that [1, 2, 3] is output after the total time has passed by 3 seconds. Contrast this with the example above, which executes multiple Futures sequentially and asynchronously.
var future1 = new Future.delayed(new Duration(seconds: 1), () => 1);
var future2 =
new Future.delayed(new Duration(seconds: 2), () => 2);
var future3 = new Future.delayed(new Duration(seconds: 3), () => 3);
Future.wait({future1,future2,future3}).then(print).catchError(print); [1, 2, 3]Copy the code
If future2 and future3 are raised with an error, future.wait will result in the error value of this future2.
var future1 = new Future.delayed(new Duration(seconds: 1), () => 1); Var future2 =new future.delayed (new Duration(seconds: 2), () => throw "throw error2"); Var future3 = new future.delayed (new Duration(seconds: 3), () => throw "throw error3");
Future.wait({future1,future2,future3}).then(print).catchError(print); // Throw error2Copy the code
Future. Any (futures)
Returns the result of the first future executed, regardless of whether the result is correct or error. (I can’t think of a scenario where this would be used.)
For example, in the following example, three different futures were created using future.delayed (), and the first completion returns the result of the Future that was delayed by 1 second.
Future
.any([1, 2, 5].map(
(delay) => new Future.delayed(new Duration(seconds: delay), () => delay)))
.then(print)
.catchError(print);
Copy the code
Future.doWhile()
Similar to the Java use of doWhile, repeating an action until false or Future is returned to exit the loop.
Usage scenario: Suitable for some scenarios that require recursive operations.
For example, I want to climb the commodity classification data of a platform, and then there are corresponding sub-categories under each category. Then I have to take the catId of the parent category and request the interface to get all the subcategories under that category. Similarly, do the same for all subcategories, recursing until the category is a leaf node, i.e., there is no subcategory under the node (there is a field where LEAF is true). Haha, I didn’t post the code, but it’s just a recursive operation until the condition is satisfied and the future exits.
For example, in the following example, generate a random number and wait until the operation ends after 10 seconds.
void futureDoWhile(){
var random = new Random();
var totalDelay = 0;
Future
.doWhile(() {
if (totalDelay > 10) {
print('total delay: $totalDelay seconds');
return false;
}
var delay = random.nextInt(5) + 1;
totalDelay += delay;
return new Future.delayed(new Duration(seconds: delay), () {
print('waited $delay seconds');
return true;
});
})
.then(print)
.catchError(print); } // Output result: I/flutter (11113): waited 5 seconds I/flutter (11113): waited 1 seconds I/flutter (11113): waited 3 seconds I/flutter (11113): waited 2 seconds I/flutter (11113): total delay: 12 seconds I/flutter (11113): nullCopy the code
Future.microtask(FutureOr computation())
Create a Future that runs on a MicroTask queue.
As mentioned above, the MicroTask queue has a higher priority than the Event queue, and futures are usually executed on the Event queue, so futures created by MicroTask will be executed before other futures.
For example, the following code,
Future((){
print("Future event 1");
});
Future((){
print("Future event 2");
});
Future.microtask((){
print("microtask event"); }); // MicroTask event //Future Event 1 //Future Event 2Copy the code
Process the result of the Future
Flutter provides the following three methods to register callbacks and listen for the result of processing the Future.
Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError});
Future<T> catchError(Function onError, {bool test(Object error)});
Future<T> whenComplete(FutureOr action());
Copy the code
Future. Then ()
Used to add a callback when the Future is complete.
Note that the return value of then () is also a Future object. So we can use the chained method to use the Future, taking the output of the previous Future as the input of the next Future, which can be written as a chained call.
For example, the following code takes the previous future result as input to the future.
Future.value(1).then((value) {
return Future.value(value + 2);
}).then((value) {
return Future.value(value + 3);
}).then(print); // Prints 6Copy the code
Future. CathcError ()
Register a callback to handle Future with error
new Future.error('boom! ').catchError(print);
Copy the code
The then method also has an onError parameter, which can also be used to handle the wrong Future.
The difference between onError and onError is that onError can only handle the current error Future, not any other Future that has an error. CatchError can catch all errors thrown in the Future chain.
So the usual practice is to catch all errors in the Future using catchError, and the onError method in the THEN method is not recommended. Otherwise, it would be cumbersome to add onError callbacks to each future’s then methods, and the code would look a bit messy.
Here are two examples of catching errors.
If you add an onError callback to the then method of the future that threw the error, onError will be called first
Future.value(1).then((value) {
return Future.value(value + 2);
}).then((value) {
throw "error";
}).then(print, onError: (e) {
print("onError find a error");
}).catchError((e) {
print("catchError find a error"); }); OnError find an errorCopy the code
Use catchError to listen for errors thrown in a chain call to the Future.
Future.value(1).then((value) {
throw "error";
}).then((value) {
return Future.value(3);
}).then(print).then((value) {
}).catchError((e) {
print("catchError find a error"); }); CatchError find an error"
Copy the code
Future.whenComplete
Similar to finally in Java, future. whenComplete is always called after the Future is complete, regardless of whether the result of the Future is correct or wrong.
Note that future. whenComplete returns a Future object.
Future.delayed(Duration(seconds: 3),(){
print("Ha ha");
}).whenComplete((){
print("complete"); }); / / ha ha / / completeCopy the code
The most common async and await
Ha-ha, there are some uses of Future mentioned above, some of which may not be very common, just know that there is this use.
One problem is that if you have multiple futures linked together, damn, the code can become hard to read.
So, you can use the Future with async and await to make the code look like synchronous code, but in fact they are still executed asynchronously.
The most common uses of Future are async and await.
Note: await can only occur in async functions. Async function that returns a Future object. If no Future object is returned, the returned value is automatically wrapped as a Future object. Catch errors, typically using try/catch mechanisms for exception handling. To await a future, we can get the result of the future and wait until we get the result to execute the next code.
For example, in the following example, create a Future with a delay of 3 seconds and return a result of 1, use await to get the value of the Future.
void main() async {
var future = new Future.delayed(new Duration(seconds: 3), () {
return 1;
});
var result = await future;
print(result + 1); } // The output is 2Copy the code
The following code structure, written like Java, uses try-catch-finally to catch errors.
try {
var result1 = await Future.value(1);
print(result1); Var result2 = await future. value(2);print(result2); 2} catch (e) {// Catch error} finally {}Copy the code
conclusion
- Several ways to create a Future
- Use then, catchError, whenComplete to handle Future results
- Use of async and await
The next step
Learn more and organize more. Damn, lazy again for a long time…