Asynchronous support
Today I will introduce the last section of Dart learning, including the use of asynchronously, generator syntax, and type alias.
There are a lot of returns in the Dart class libraryFuture
orStream
Functions of the object. These functions are calledAsynchronous functions: They will only return after setting up some time-consuming operations, such as IO operations. Instead of waiting for this operation to be completed.
at the same time,async
andawait
Keywords support asynchronous programming, allowing you to write asynchronous code that is much like synchronous code.
Future
Future
With JavaScriptPromise
Very similar, representing the final completion (or failure) of an asynchronous operation and its result value. Simply put, it is used to handle asynchronous operations. If the asynchronous processing is successful, it will be successful. If the asynchronous processing fails, it will catch errors or stop subsequent operations.A Future will only correspond to one result, either success or failure.
Note: Future
The return value of all APIs is still oneFuture
Object, so it can be easily chained calls.
For the convenience of the example, use it in this exampleCreated a delay task (the actual scenario will be a real time-consuming task, such as a network request), that is, return the result string after 2 seconds
hi world!
, and then we are inthen
Receive asynchronous results and print the results. The code is as follows:
(new Duration(seconds: 2),(){ return "hi world!"; }).then((data){ print(data); });
If an error occurs in an asynchronous task, you cancatchError
Catch the error in the above example to:
(new Duration(seconds: 2),(){ //return "hi world!"; throw AssertionError("Error"); }).then((data){ //The execution will come here after success print("success"); }).catchError((e){ //The execution failure will come here print(e); });
then
There is also an optional parameter for the methodonError
, it can also catch exceptions:
(new Duration(seconds: 2), () { //return "hi world!"; throw AssertionError("Error"); }).then((data) { print("success"); }, onError: (e) { print(e); });
Sometimes, we encounter scenarios where we need to do something regardless of whether the asynchronous task execution is successful or failed, such as popping up a load dialog before a network request and closing the dialog box after the request is over. There are two ways to do this scenario. The first is tothen
orcatch
Close the dialog box, the second method is to use itFuture
ofwhenComplete
For callback, we will change the above example:
(new Duration(seconds: 2),(){ //return "hi world!"; throw AssertionError("Error"); }).then((data){ //The execution will come here after success print(data); }).catchError((e){ //The execution failure will come here print(e); }).whenComplete((){ //It will come here regardless of success or failure});
useCan do multiple
Future
The subsequent operations will be performed only when departure is done at the same time, the same as in JavaScript()
method.
Accept one
Future
Array parameters, only all in the arrayFuture
It will only be triggered after all execution is successfulthen
Successful callback, as long as there is oneFuture
If the execution fails, an error callback will be triggered. Below, we pass the simulationTo simulate the asynchronous tasks that obtain two data. When both asynchronous tasks are successfully executed, the results of the two asynchronous tasks are spliced and printed out. The code is as follows:
([ //Return the result after 2 seconds (new Duration(seconds: 2), () { return "hello"; }), //Return the result after 4 seconds (new Duration(seconds: 4), () { return " world"; }) ]).then((results){ print(results[0]+results[1]); }).catchError((e){ print(e); }); /* Finally, the result will be obtained in 4 seconds */
For more Future APIs, please check the documentation yourself.
async and await
Asynchronous functions are usedasync
Function marked by modifier. Add to the functionasync
The keyword will return it to a Future.
String lookUpVersion() => '1.0.0'; // Return to String
Future<String> lookUpVersion() async => '1.0.0'; // Return to Future<String>
Then we can useawait
Keywords directly accept a Future'sthen
The successful callback is just like in JavaScript:
task() async { try{ String id = await login("alice","******"); String userInfo = await getUserInfo(id); await saveUserInfo(userInfo); // Perform the next operation } catch(e){ // Error handling print(e); } }
-
async
Used to indicate that the function is asynchronous, the defined function will return aFuture
Object, you can use the then method to add callback functions. -
await
Behind is oneFuture
, means that the asynchronous task will be completed and will not go down after it is completed asynchronously. Notice,await
Must appear inasync
inside the function.
Notice:The body of the function does not need to use Future's API. Dart will create if requiredFuture
object. If no useful value is returned, return itFuture<void>
type.
Processing Stream
Stream
It is also used to receive asynchronous event data, andFuture
The difference is that it can receive the results of multiple asynchronous operations (success or failure). That is, when executing an asynchronous task, the result data or error exception can be passed by multiple triggering success or failure events.Stream
It is often used in asynchronous task scenarios that read data multiple times, such as network content download, file reading and writing, etc.
When you need to get the value from the Stream, there are two options:
useasync
and asynchronousfor
cycle(await for
)
Note:In useawait for
Before, make sure it makes the code clearer and really want to wait for all results of the stream. For example, it should not be used for UI eventsawait
, because the UI framework sends endless streams of events.
asynchronousfor
The loop takes the following form:
await for (varOrType identifier in expression) { // Executes each time the stream emits a value. }
The value of the expression must have a Stream type. The execution process is as follows:
Wait for the stream to emit value.
implementfor
The body of the loop and set the variable to the emitted value.
Repeat 1 and 2 until the stream is closed.
To stop listening to streams, you can usebreak
orreturn
statement, the statement will jump outfor
Loop and unsubscribe from the stream.
If asynchronous is implementedfor
Compile-time error occurred while looping, please make sureawait
In an asynchronous function. For example, to be in the applicationmain()
Use asynchronous in functionsfor
cycle,main()
The subject must be marked asasync
:
Future main() async { // ... await for (var request in requestServer) { handleRequest(request); } // ... }
Use Stream API, as described in [Bootdown of Library]
([ //Return the result after 1 second (new Duration(seconds: 1), () { return "hello 1"; }), // Throw an exception (new Duration(seconds: 2),(){ throw AssertionError("Error"); }), //Return the result after 3 seconds (new Duration(seconds: 3), () { return "hello 3"; }) ]).listen((data){ print(data); }, onError: (e){ print(); }, onDone: (){ }); /* The above code will output in turn: I/flutter (17666): hello 1 I/flutter (17666): Error I/flutter (17666): hello 3 */
Generator
Consider using generator functions when it is necessary to generate a sequence of values in a delay.
Dart supports two generator functions in built-in:
- Synchronous generator: Returns Iterable object
- Asynchronous generator: Returns Stream object
To implement a synchronous generator function, mark the function body assync*
and useyield
Statement passes value:
Iterable<int> naturalsTo(int n) sync* { int k = 0; while (k < n) yield k++; }
To implement an asynchronous generator function, mark the function body asasync*
and useyield
Statement passes value:
Stream<int> asynchronousNaturalsTo(int n) async* { int k = 0; while (k < n) yield k++; }
If the generator is recursive, you can useyield*
To improve its performance:
Iterable<int> naturalsDownFrom(int n) sync* { if (n > 0) { yield n; yield* naturalsDownFrom(n - 1); } }
Type definition
In Dart, functions are objects, just as strings and numbers are objects.typedef
orfunction-type
Provides a type alias for the function that can be used when declaring fields and return types. When the function type is assigned to a variable,typedef
Keep type information.
The following code is not usedtypedef
:
class SortedCollection { Function compare; SortedCollection(int f(Object a, Object b)) { compare = f; } } // Initial, broken implementation. int sort(Object a, Object b) => 0; void main() { SortedCollection coll = SortedCollection(sort); // All we know is that compare is a function, // but what type of function? assert( is Function); }
In the above code,compare
Type information is lost when f is allocated.f
The type is(Object, Object)->int(int represents the return value type)
,certainly,compare
The type isFunction
. If we change the code to use explicit names and retain type information, both developers and tools can use this information.
typedef Compare = int Function(Object a, Object b); class SortedCollection { Compare compare; SortedCollection(); } // Initial, broken implementation. int sort(Object a, Object b) => 0; void main() { SortedCollection coll = SortedCollection(sort); assert( is Function); assert( is Compare); }
Notice:at present,typedefs
Only function types may change later.
becausetypedef
Just alias, so they provide a way to check any function type. For example:
typedef Compare<T> = int Function(T a, T b); int sort(int a, int b) => a - b; void main() { assert(sort is Compare<int>); // True! }
Metadata
Use metadata to provide additional information about the code. Metadata comments in characters@
Start with a compilation constant (e.g.deprecated
) reference or call to a constant constructor.
All dart codes can use two comments:@deprecated
(Deprecated comments) and@override
. There is a use here@deprecated
Example of comments:
class Television { /// _Deprecated: Use [turnOn] instead._ @deprecated void activate() { turnOn(); } /// Turns the TV's power on. void turnOn() {...} }
You can define your own metadata annotations (that is, the effect similar to the decorator in JavaScript). Here is an example defining the @todo annotation with two parameters:
library todo; class Todo { final String who; final String what; const Todo(, ); }
There is a use here@todo
Examples of comments:
import ''; @Todo('seth', 'make this do something') void doSomething() { print('do something'); }
Metadata can appear before a library, class, type definition, type parameter, constructor, factory, function, field, parameter, or variable declaration, or before importing or exporting instructions. Metadata can be retrieved at runtime using reflection.
Use of core library
You can refer to the introduction in the official documentation:A tour of the core libraries
The above is a detailed explanation of the usage of Dart asynchronous programming generator and custom types. For more information about Dart asynchronous programming generator, please pay attention to my other related articles!