Le premier Dart
est un langage monothread, donc Dart
le 异步操作
bon support nous permet Dart
d'effectuer des opérations chronophages de manière asynchrone lors de l' écriture de programmes. Pour que vous puissiez effectuer d'autres opérations en attendant la fin d'une opération. Voici quelques opérations asynchrones courantes:
-
Obtenez des données via le réseau.
-
Écrivez dans la base de données.
-
Lisez les données du fichier.
Pour Dart
effectuer des opérations asynchrones dans, vous pouvez utiliser des Future
classes async
et des await
mots - clés.
# Boucle d'événements de Dart (boucle d'événements)
Dans Dart
, il existe en fait deux types de files d'attente:
-
File d' attente d'événements (
event queue
), y compris tous externesI/O
événements:mouse events
,drawing events
,timers
,,isolate
transfert de l' information entre les deux. -
La file d'attente de micro-tâches (
microtask queue
) représente une tâche asynchrone qui sera achevée en peu de temps. Il a la priorité la plus élevée, plus élevée que celaevent queue
, tant qu'il y a des tâches dans la file d'attente, il peut toujours occuper la boucle d'événements.microtask queue
Les tâches ajoutées sont principalementDart
générées en interne.
Parce que
microtask queue
la priorité est plus élevéeevent queue
, s'ilmicrotask queue
y a trop de microtâches, il peut occuper celle actuelleevent loop
. Ainsievent queue
, des événements extérieurs tels que le toucher et le dessin au centre provoquent un blocage et une stagnation.
Dans chaque boucle d'événements, Dart
passez toujours à la première microtask queue
pour vérifier s'il existe des tâches exécutables, sinon, les event queue
processus suivants seront traités.
Les tâches asynchrones que nous utilisons le plus sont celles dont la priorité est inférieure event queue
. Fournit une couche d'encapsulation Dart
pour event queue
l'établissement des tâches, que nous Dart
utilisons souvent dans Future
.
Dans des circonstances normales, Future
l'exécution d' une tâche asynchrone est relativement simple:
-
Lorsqu'une
Future
est déclarée ,Dart
le corps d'exécution de la fonction de la tâche asynchrone est placéevent queue
, puis retourne immédiatement, et le code suivant continue de s'exécuter de manière synchrone. -
Lorsque l'exécution du code d'exécution synchrone est terminée,
event queue
il sera ajouté conformément àevent queue
l'ordre (c'est-à-dire l'ordre de déclaration) sont séquentiellement retirés de l'événement, et enfin la synchronisation exécutantFuture
le corps de la fonction et les opérations suivantes.
# Futur
Future<T>
Classe, qui représente un T
type de résultat d'opération asynchrone. Si l'opération asynchrone ne nécessite pas de résultat, le type est Future<void>
. En d'autres termes, il Future
s'agit d'abord d'une classe générique et le type peut être spécifié. S'il n'y a pas de type correspondant, alors Future
il effectuera un type de dérivation dynamique.
# Utilisation de base future
# Futur constructeur d'usine
Qu'est-ce que le constructeur d'usine ?
Le constructeur de fabrique est une sorte de constructeur. Contrairement aux constructeurs ordinaires, la fonction de fabrique ne génère pas automatiquement une instance, mais détermine l'objet d'instance renvoyé par le biais de code.
DansDart
, le mot clé du constructeur d'usine estfactory
. Nous savons que le constructeur inclut un constructeur de nom de classe et un constructeur nommé,factory
qui devient un constructeur d'usine après avoir été ajouté avant le constructeur. En d'autres termesfactory
, il peut être placé avant la fonction de nom de classe ou avant la fonction nommée.
Ci-dessous, nous passons Future
le constructeur d'usine pour créer le plus simple Future
.
Comme vous pouvez le voir, Future
le constructeur d'usine reçoit une Dart
fonction en tant que paramètre. Cette fonction n'a pas de paramètres et la valeur de retour est FutureOr<T>
type.
Il ressort du résultat imprimé que Future
lorsque le résultat n'est pas nécessaire, le type renvoyé est Future<void>
.
Notez que le jugement de type est effectué en premier, puis Future
l'opération au cours de l' impression .
# async
Etawait
La valeur par défaut Future
est de s'exécuter de manière asynchrone. Si vous voulez notre Future
exécution synchrone, vous pouvez passer des mots async
- await
clés:
Comme vous pouvez le voir, le nôtre Future
a été exécuté de manière synchrone. await
Attendra Future
la fin de l'exécution avant de continuer à exécuter le code suivant.
La async
somme des mots-clés await
fait partie de la prise en charge asynchroneDart
du langage .
Les fonctions asynchrones sont des fonctions qui contiennent des mots-clés dans l'en-tête de fonction
async
.
async: utilisé pour indiquer que la fonction est asynchrone et que la fonction définie renvoie un Future
objet.
attendre: suivi d'un Future
, ce qui signifie attendre la fin de la tâche asynchrone, puis continuer l'exécution après l'achèvement de la tâche asynchrone. await
Ne peut apparaître que dans les fonctions asynchrones . Cela nous permet d'effectuer des tâches asynchrones comme l'écriture de code synchrone sans utiliser de callbacks.
Une fois l'impression terminée, il commencera à vérifier
microtask queue
s'il contient des tâches et s'il y a des tâches, il sera exécuté jusqu'à ce que lamicrotask queue
file d'attente soit vide. Parce quemicrotask queue
la priorité est la plus élevée. Ensuite, allez exécuterevent queue
. Généralement, lesFuture
événements créés seront insérés etevent queue
exécutés dans l'ordre (Future.microtask
sauf pour la méthode d' utilisation ).
Remarque : Dans
Dart
, il neasync/await
s'agit que d'un sucre syntaxique, le compilateur ou l'interpréteur finira par le convertir en unePromise(Future)
chaîne d'appels.
Avant Dart 2.0, la fonction async retournait immédiatement sans exécuter de code dans le corps de la fonction async.
Donc, si nous modifions le code sous la forme suivante:
Lorsque nous utilisons des async
mots-clés, cela signifie que la testFuture
fonction est devenue une fonction asynchrone.
Ainsi, testFuture
l'impression après la fonction sera exécutée en premier .
Une fois l'impression terminée, il commencera à vérifier
microtask queue
s'il contient des tâches et s'il y a des tâches, il sera exécuté jusqu'à ce que lamicrotask queue
file d'attente soit vide. Parce quemicrotask queue
la priorité est la plus élevée. Ensuite, allez exécuterevent queue
. Généralement, lesFuture
événements créés seront insérés etevent queue
exécutés dans l'ordre (Future.microtask
sauf pour la méthode d' utilisation ).
# Valeur future()
Créez-en un qui renvoie la value
valeur spécifiée Future
:
void testFuture() async {
var future = await Future.value(1);
print("future value: $future.");
}
testFuture();
print("在testFuture()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
future value: 1.
# Future.delayed ()
Créez une exécution différée Future
:
void testFuture() async {
Future.delayed(Duration(seconds: 2), () {
print("Future.delayed 2 seconds.");
});
}
testFuture();
print("在testFuture()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
Future.delayed 2 seconds.
# Future
Simple à utiliser
# Future
Résultat du traitement
Par exemple Future
, si le processus asynchrone réussit, l'opération réussie est exécutée et si le processus asynchrone échoue, l'erreur est interceptée ou l'opération suivante est arrêtée. On Future
ne correspondra qu'à un seul résultat, succès ou échec.
Veuillez garder à l'esprit que Future
toutes les API
valeurs de retour sont toujours un Future
objet, de sorte que les appels en chaîne peuvent être effectués facilement .
Dart
Les trois méthodes suivantes sont fournies pour traiter Future
les résultats.
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 ()
Utilisé pour enregistrer un Future
rappel à appeler une fois terminé. S'il Future
y en a plusieurs then
, ils seront exécutés de manière synchrone dans l'ordre du lien, et ils en partageront également un 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()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
6
Dans le même temps, il then()
sera Future
exécuté immédiatement après l'exécution du corps de la fonction:
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()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
a b c d
Ensuite, le problème est que si l' Future
exécution est terminée, nous obtiendrons Future
la référence à cela , puis continuerons d'appeler la then()
méthode. Alors, Dart
comment cette situation sera-t-elle gérée en ce moment? Dans ce cas, Dart
le then()
corps de méthode qui sera ajouté ultérieurement sera inséré microtask queue
et exécuté dès que possible:
-
Comme la
testFuture()
fonction est appelée en premier , elle est imprimée en premierfuture 13
. -
Ensuite, effectuez l'
testFuture()
impression suivante. -
Démarrez l'exécution de la tâche asynchrone.
-
Effectuez d'abord la
microtask queue
tâche la plus prioritairescheduleMicrotask
, imprimezfuture 12
. -
Puis
Future
exécutez à nouveau dans l'ordre de déclaration et imprimezfuture 1
. -
Ensuite
futureFinish
, imprimezfuture 2
. L'futureFinish
exécution est maintenant terminée. Donc, ilDart
sera mis dansfutureFinish
lathen
méthode qui sera appelée plus tardmicrotask queue
. En raisonmicrotask queue
de la plus haute priorité. Par conséquentfutureFinish
, ilthen
sera exécuté en premier et impriméfuture 11
. -
Continuez ensuite à exécuter à l'
event queue
intérieurfuture 3
. Puis exécutezthen
et imprimezfuture 4
. Dans le même tempsthen
,microtask queue
une micro-tâche a été ajoutée à la méthode . Puisqu'il est en cours d'exécution à ce momentevent queue
, il ne sera pas exécuté avant la prochaine boucle d'événements. Par conséquent, l'then
exécution et l'impression synchrones suivantes se poursuiventfuture 6
. Cette boucle d'événements se termine et la boucle d'événements suivante prendfuture 5
cette microtâche et l'imprimefuture 5
. -
microtask queue
La tâche est terminée. Continuez à effectuerevent queue
les tâches dans. Imprimerfuture 7
. Puis exécutezthen
. Ce qu'il faut noter ici, c'est que lethen
retour à ce moment est un retour nouvellement crééFuture
. Donc cecithen
et les suivantsthen
y seront ajoutésevent queue
. -
Continuez à effectuer
evnet queue
les tâches à l'intérieur dans l'ordre et imprimezfuture 10
. -
Dans la dernière boucle d'événements, retirez la méthode nouvellement ajoutée
evnet queue
passée à l'intérieur , et la suivante , print.future 7
then
future 8
future 9
-
L'ensemble du processus est terminé.
# Future.catchError
Enregistrer un rappel pour capturer Future
le error
:
void testFuture() async {
new Future.error('Future 发生错误啦!').catchError(print, test: (error) {
return error is String;
});
}
testFuture();
print("在testFuture()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
Future 发生错误啦!
# then
Rappel onError
etFuture.catchError
Future.catchError
Le rappel ne gère que Future
l'erreur générée par l' original , pas l'erreur générée par la fonction de rappel, et onError ne peut gérer que l'erreur du Future actuel:
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()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
error: Future 发生错误啦!
handle new error: new error2
# Future.whenComplete
Future.whenComplete
Il sera toujours appelé une fois le futur terminé, qu'il soit terminé en raison d'une erreur ou terminé normalement. Par exemple, la boîte de dialogue de chargement apparaît avant la demande réseau et la boîte de dialogue se ferme une fois la demande terminée. Et renvoyez un objet Future:
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()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
Future 发生错误啦!
Future whenComplete!
在testFuture()执行之后打印。
Future 正常
Future whenComplete!
# Utilisation avancée future
# Future.timeout
Il aurait été Future
terminé après 2 s, mais il a été timeout
déclaré expirer après 1 s, donc après 1 s, il Future
lancera 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()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
TimeoutException after 0:00:01.000000: Future not completed
# Future.foreach
Basé sur un objet de collection, créez une série de Future
. Et les exécutera dans l'ordre Future
. Par exemple, créez 3 retards correspondant au nombre de secondes basé sur {1,2,3} Future
. Le résultat de l'exécution est que 1 est imprimé après 1 seconde, 2 est imprimé après 2 secondes et 3 est imprimé après 3 secondes. Le temps total est de 6 secondes:
void testFuture() async {
Future.forEach({1,2,3}, (num){
return Future.delayed(Duration(seconds: num),(){print("第$num秒执行");});
});
}
testFuture();
print("在testFuture()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
第1秒执行
第2秒执行
第3秒执行
# Future.wait
Attendez plusieurs Future
achèvements et récupérez leurs résultats. Il existe deux situations:
Tous Future
ont des résultats normaux renvoyés. Le Future
résultat est le retour de tous les Future
ensembles de résultats spécifiés :
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()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
[1, 2, 3]
Future
Une erreur s'est produite dans un ou plusieurs d'entre eux et s'est produite error
. Le Future
résultat renvoyé est la première erreur de la Future
valeur de:
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()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
Future 发生错误啦!
Grâce à cet article, nous comprenons la relation entre Dart
la boucle d'événements et event queue
et microtask queue
. Dans le même temps, Dart Future
une utilisation de base et une utilisation avancée sont introduites, et quelques exemples d'utilisation sont entrecoupés pour aider tout le monde à mieux comprendre Dart
le fonctionnement asynchrone. Bien sûr, il existe des connaissances sur la Dart
programmation asynchrone et le multi-threading, pas trop impliquées ici. Je continuerai à vous l'expliquer dans les articles suivants.
# Future.any
Ce qui est renvoyé est Future
le résultat de la première exécution , que le résultat soit correct ou 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()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
1
# Future.doWhile
Exécutez une action à plusieurs reprises jusqu'à ce qu'elle renvoie false ou Future, puis quittez la boucle. Elle convient à certains scénarios qui nécessitent des opérations récursives:
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()执行之后打印。");
Résultats du:
在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
La synchronisation exécutera ses paramètres dans la fonction, puis planifiera d' microtask queue
être effectuée elle-même. C'est une tâche de blocage, qui bloquera le code actuel. Une fois sync
la tâche exécutée, le code peut passer à la ligne suivante:
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()执行之后打印。");
Résultats du:
Future sync microtask event 2
在testFuture()执行之后打印。
microtask event
Future event 1
Future event 3
Mais notez que si cette fonction paramétrée en renvoie une 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()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
microtask event
Future event 1
Future event 2
Future event 3
# Future.microtask
Créez-en un en microtask queue
cours d'exécution Future
. Nous savons que cette microtask queue
priorité est event queue
élevée. Le général Future
est en cours d' event queue
exécution. Ainsi, celui Future.microtask
créé Future
aura priorité sur les autres Future
exécutions:
void testFuture() async {
Future((){
print("Future event 1");
});
Future((){
print("Future event 2");
});
Future.microtask((){
print("microtask event");
});
}
testFuture();
print("在testFuture()执行之后打印。");
Résultats du:
在testFuture()执行之后打印。
microtask event
Future event 1
Future event 2
# Écrit à la fin
Grâce à cet article, nous comprenons la relation entre Dart
la boucle d'événements et event queue
et microtask queue
. Dans le même temps, Dart Future
une utilisation de base et une utilisation avancée sont introduites, et quelques exemples d'utilisation sont entrecoupés pour aider tout le monde à mieux comprendre Dart
le fonctionnement asynchrone. Bien sûr, il existe des connaissances sur la Dart
programmation asynchrone et le multi-threading, pas trop impliquées ici. Je continuerai à vous l'expliquer dans les articles suivants.