The first Dart
is a single-threaded language, so Dart
the 异步操作
right support allows us Dart
to perform time-consuming operations asynchronously when writing programs. So that you can perform other operations while waiting for one operation to complete. Here are some common asynchronous operations:
-
Get data through the network.
-
Write to the database.
-
Read data from the file.
To Dart
perform asynchronous operations in, you can use Future
classes async
and await
keywords.
# Dart's event loop (event loop)
In Dart
, there are actually two types of queues:
-
Event queue (
event queue
), including all externalI/O
events:mouse events
,drawing events
,timers
, ,isolate
transfer of information between. -
Micro task queue (
microtask queue
), represents an asynchronous task that will be completed in a short time. It has the highest priority, higher than thatevent queue
, as long as there are tasks in the queue, it can always occupy the event loop.microtask queue
The added tasks are mainlyDart
generated internally.
Because
microtask queue
the priority is higherevent queue
, ifmicrotask queue
there are too many microtasks, it may occupy the current oneevent loop
. Thusevent queue
, external events such as touch and drawing in the center cause blocking and stagnation.
In each event loop, Dart
always go to the first one microtask queue
to check whether there are executable tasks, if not, then the subsequent event queue
processes will be processed.
The asynchronous tasks we use the most are the ones with lower priority event queue
. Provides a layer of encapsulation Dart
for event queue
the establishment of tasks, which we Dart
often use in Future
.
Under normal circumstances, Future
the execution of an asynchronous task is relatively simple:
-
When one
Future
is declared ,Dart
the function execution body of the asynchronous task is put inevent queue
, and then returns immediately, and the subsequent code continues to execute synchronously. -
When synchronous execution code execution is completed,
event queue
it will be added in accordance withevent queue
the order (i.e. declaration order) are sequentially taken out event, and finally the synchronization executingFuture
the function body, and subsequent operations.
# Future
Future<T>
Class, which represents a T
type of asynchronous operation result. If the asynchronous operation does not require a result, the type is Future<void>
. In other words, the first Future
is a generic class, you can specify the type. If no corresponding type, then Future
it will perform a dynamic derivation type.
# Future basic usage
# Future factory constructor
What is the factory constructor ?
The factory constructor is a kind of constructor. Unlike ordinary constructors, the factory function does not automatically generate an instance, but determines the returned instance object through code.
InDart
, the keyword of the factory constructor isfactory
. We know that the constructor includes a class name constructor and a named constructor,factory
which becomes a factory constructor after being added before the constructor. In other wordsfactory
, it can be placed before the class name function or before the named function.
Below we pass Future
the factory constructor to create the simplest one Future
.
As you can see, Future
the factory constructor receives a Dart
function as a parameter. This function has no parameters and the return value is the FutureOr<T>
type.
It can be seen from the printed result that Future
when the result is not needed, the returned type is Future<void>
.
Note that the type judgment is performed first, and then Future
the operation within the printing .
# async
Andawait
The default Future
is to run asynchronously. If you want our Future
synchronous execution, you can pass async
and await
keywords:
As you can see, ours Future
has been executed synchronously. await
Will wait Future
for the end of execution before continuing to execute the following code.
Keyword async
sum await
is part of the Dart
language's asynchronous support .
Asynchronous functions are functions that contain keywords in the function header
async
.
async: Used to indicate that the function is asynchronous, and the defined function returns an Future
object.
await: followed by one Future
, which means to wait for the completion of the asynchronous task, and then continue execution after the completion of the asynchronous task. await
Can only appear inside asynchronous functions . It allows us to perform asynchronous tasks like writing synchronous code without using callbacks.
After printing is finished, it will start to check
microtask queue
whether there are tasks in it, and if there are tasks, it will be executed until themicrotask queue
queue is empty. Becausemicrotask queue
the priority is the highest. Then go to executeevent queue
. Generally, theFuture
created events will be inserted andevent queue
executed in order (Future.microtask
except for the usage method).
Note : In
Dart
, itasync/await
is just a syntactic sugar, the compiler or interpreter will eventually convert it into aPromise(Future)
call chain.
Before Dart 2.0, the async function would return immediately without executing any code in the async function body.
So, if we change the code to the following form:
When we use async
keywords, it means that the testFuture
function has become an asynchronous function.
So testFuture
the printing after the function will be executed first .
After printing is finished, it will start to check
microtask queue
whether there are tasks in it, and if there are tasks, it will be executed until themicrotask queue
queue is empty. Becausemicrotask queue
the priority is the highest. Then go to executeevent queue
. Generally, theFuture
created events will be inserted andevent queue
executed in order (Future.microtask
except for the usage method).
# Future.value()
Create one that returns the specified value
value Future
:
void testFuture() async {
var future = await Future.value(1);
print("future value: $future.");
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
future value: 1.
# Future.delayed()
Create a delayed execution Future
:
void testFuture() async {
Future.delayed(Duration(seconds: 2), () {
print("Future.delayed 2 seconds.");
});
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
Future.delayed 2 seconds.
# Future
Simple to use
# Processing Future
result
For example Future
, if the asynchronous process succeeds, the successful operation is executed, and if the asynchronous process fails, the error is caught or the subsequent operation is stopped. One Future
will only correspond to one result, either success or failure.
Please remember that Future
all API
the return value is still an Future
object, so it can be easily chained .
Dart
The following three methods are provided to process Future
the results.
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());
# Future.then()
Used to register a Future
callback to be called upon completion. If Future
there are more than one then
, they will be executed synchronously in the order of the link, and they will also share one event loop
.
void testFuture() async {
Future.value(1).then((value) {
return Future.value(value + 2);
}).then((value) {
return Future.value(value + 3);
}).then(print);
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
6
At the same time, it then()
will be Future
executed immediately after the function body is executed:
void testFuture() async {
var future = new Future.value('a').then((v1) {
return new Future.value('$v1 b').then((v2) {
return new Future.value('$v2 c').then((v3) {
return new Future.value('$v3 d');
});
});
});
future.then(print, onError: print);
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
a b c d
Then the problem is coming. If the Future
execution has been completed, we will get Future
the reference to this , and then continue to call the then()
method. So Dart
how will this situation be handled at this time? In this case, Dart
the then()
method body that will be added later will be put in microtask queue
and executed as soon as possible:
-
Because the
testFuture()
function is called first , it is printed firstfuture 13
. -
Then perform the
testFuture()
following printing. -
Start asynchronous task execution.
-
Perform the highest priority
microtask queue
task firstscheduleMicrotask
, printfuture 12
. -
Then
Future
execute again in the order of declaration and printfuture 1
. -
Then there
futureFinish
, printfuture 2
. ThefutureFinish
execution is now complete. So itDart
will be put infutureFinish
thethen
method that will be called latermicrotask queue
. Becausemicrotask queue
of the highest priority. ThereforefutureFinish
, itthen
will be executed first and printedfuture 11
. -
Then continue to execute
event queue
insidefuture 3
. Then executethen
and printfuture 4
. At the same timethen
,microtask queue
a micro task was added to the method . Because it is being executed at this timeevent queue
, it will not be executed until the next event loop. Therefore, the subsequentthen
synchronous execution and printing are continuedfuture 6
. This event loop ends, and the next event loop takes outfuture 5
this microtask and prints itfuture 5
. -
microtask queue
The task is completed. Continue to performevent queue
the tasks in. Printfuture 7
. Then executethen
. What needs to be noted here is: thethen
return at this time is a newly created oneFuture
. So thisthen
and the followingthen
will be added toevent queue
it. -
Continue to perform
evnet queue
the tasks inside in order and printfuture 10
. -
In the last event loop, take out the newly added method
evnet queue
passed inside , and the subsequent , print.future 7
then
future 8
future 9
-
The whole process is over.
# Future.catchError
Register a callback to capture Future
the error
:
void testFuture() async {
new Future.error('Future 发生错误啦!').catchError(print, test: (error) {
return error is String;
});
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
Future 发生错误啦!
# then
Callback onError
andFuture.catchError
Future.catchError
The callback only handles Future
the error thrown by the original , not the error thrown by the callback function, and onError can only handle the error of the current Future:
void testFuture() async {
new Future.error('Future 发生错误啦!').then((_) {
throw 'new error';
}).catchError((error) {
print('error: $error');
throw 'new error2';
}).then(print, onError:(error) {
print("handle new error: $error");
});
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
error: Future 发生错误啦!
handle new error: new error2
# Future.whenComplete
Future.whenComplete
It will always be called after the Future is completed, regardless of whether it is completed due to an error or completed normally. For example, the loading dialog box pops up before the network request, and the dialog box is closed after the request ends. And return a Future object:
void testFuture() async {
var random = new Random();
new Future.delayed(new Duration(seconds: 1), () {
if (random.nextBool()) {
return 'Future 正常';
} else {
throw 'Future 发生错误啦!';
}
}).then(print).catchError(print).whenComplete(() {
print('Future whenComplete!');
});
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
Future 发生错误啦!
Future whenComplete!
在testFuture()执行之后打印。
Future 正常
Future whenComplete!
# Future advanced usage
# Future.timeout
It would have been Future
completed after 2s, but it was timeout
declared to time out after 1s, so after 1s it Future
will throw TimeoutException
:
void testFuture() async {
new Future.delayed(new Duration(seconds: 2), () {
return 1;
}).timeout(new Duration(seconds:1)).then(print).catchError(print);
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
TimeoutException after 0:00:01.000000: Future not completed
# Future.foreach
Based on a collection object, create a series of Future
. And will execute these in order Future
. For example, create 3 delays corresponding to the number of seconds based on {1,2,3} Future
. The execution result is that 1 is printed after 1 second, 2 is printed after 2 seconds, and 3 is printed after 3 seconds. The total time is 6 seconds:
void testFuture() async {
Future.forEach({1,2,3}, (num){
return Future.delayed(Duration(seconds: num),(){print("第$num秒执行");});
});
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
第1秒执行
第2秒执行
第3秒执行
# Future.wait
Wait for multiple Future
completions and collect their results. There are two situations:
All Future
have normal results returned. The Future
result is the return of all the specified Future
set of results:
void testFuture() async {
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);
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
[1, 2, 3]
Future
An error occurred in one or several of them and occurred error
. Then Future
the return result is the first Future
value where the error occurred :
void testFuture() async {
var future1 = new Future.delayed(new Duration(seconds: 1), () => 1);
var future2 =
new Future.delayed(new Duration(seconds: 2), () {
throw 'Future 发生错误啦!';
});
var future3 = new Future.delayed(new Duration(seconds: 3), () => 3);
Future.wait({future1,future2,future3}).then(print).catchError(print);
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
Future 发生错误啦!
Through this article, we understand the relationship between Dart
the event loop and event queue
and microtask queue
. At the same time, Dart Future
some basic usage and advanced usage are introduced, and some usage examples are interspersed to help everyone better understand Dart
the asynchronous operation. Of course, there are some knowledge about Dart
asynchronous programming and multi-threading, not too much involved here. I will continue to explain it to you in subsequent articles.
# Future.any
What is returned is Future
the result of the first execution , regardless of whether the result is correct or error
:
void testFuture() async {
Future
.any([1, 2, 5].map((delay) => new Future.delayed(new Duration(seconds: delay), () => delay)))
.then(print)
.catchError(print);
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
1
# Future.doWhile
Perform an action repeatedly until it returns false or Future and exit the loop. It is suitable for some scenarios that require recursive operations:
void testFuture() async {
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);
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
waited 5 seconds
waited 5 seconds
waited 3 seconds
total delay: 11 seconds
null
waited 4 seconds
waited 3 seconds
total delay: 12 seconds
null
# Future.sync
Synchronization will perform its parameters into the function, and then schedule to microtask queue
be done themselves. It is a blocking task, which will block the current code. After sync
the task is executed, the code can go to the next line:
void testFuture() async {
Future((){
print("Future event 1");
});
Future.sync(() {
print("Future sync microtask event 2");
});
Future((){
print("Future event 3");
});
Future.microtask((){
print("microtask event");
});
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
Future sync microtask event 2
在testFuture()执行之后打印。
microtask event
Future event 1
Future event 3
But note that if this parameterized function returns one Future
:
void testFuture() async {
Future((){
print("Future event 1");
});
Future.sync(() {
return Future(() { print("Future event 2");
});
});
Future((){
print("Future event 3");
});
Future.microtask((){
print("microtask event");
});
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
microtask event
Future event 1
Future event 2
Future event 3
# Future.microtask
Create a microtask queue
running one Future
. We know that microtask queue
priority than event queue
high. The general Future
is in event queue
execution. So the Future.microtask
created one Future
will take precedence over other Future
executions:
void testFuture() async {
Future((){
print("Future event 1");
});
Future((){
print("Future event 2");
});
Future.microtask((){
print("microtask event");
});
}
testFuture();
print("在testFuture()执行之后打印。");
Results of the:
在testFuture()执行之后打印。
microtask event
Future event 1
Future event 2
# Written at the end
Through this article, we understand the relationship between Dart
the event loop and event queue
and microtask queue
. At the same time, Dart Future
some basic usage and advanced usage are introduced, and some usage examples are interspersed to help everyone better understand Dart
the asynchronous operation. Of course, there are some knowledge about Dart
asynchronous programming and multi-threading, not too much involved here. I will continue to explain it to you in subsequent articles.