Programmation asynchrone dans Dart-Future, asynchrone et attend

Le premier Dartest un langage monothread, donc Dartle 异步操作bon support nous permet Dartd'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 Darteffectuer des opérations asynchrones dans, vous pouvez utiliser des Futureclasses asyncet des awaitmots - clés.

 

# Boucle d'événements de Dart (boucle d'événements)

Dans Dart, il existe en fait deux types de files d'attente:

  1. File d' attente d'événements ( event queue), y compris tous externes I/Oévénements: mouse events, drawing events, timers,, isolatetransfert de l' information entre les deux.

  2. 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 cela event queue, tant qu'il y a des tâches dans la file d'attente, il peut toujours occuper la boucle d'événements. microtask queueLes tâches ajoutées sont principalement  Dartgénérées en interne.

Parce que  microtask queue la priorité est plus élevée  event queue , s'il  microtask queuey a trop de microtâches, il peut occuper celle actuelle event loop. Ainsi event 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, Dartpassez toujours à la première microtask queuepour vérifier s'il existe des tâches exécutables, sinon, les event queueprocessus 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 Dartpour  event queuel'établissement des tâches, que nous Dartutilisons souvent dans Future.

Dans des circonstances normales, Future l'exécution d' une  tâche asynchrone est relativement simple:

 

  1. 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.

  2. Lorsque l'exécution du code d'exécution synchrone est terminée, event queueil sera ajouté conformément à event queuel'ordre (c'est-à-dire l'ordre de déclaration) sont séquentiellement retirés de l'événement, et enfin la synchronisation exécutant  Future 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 Futures'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 Futureil 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.
Dans Dart, le mot clé du constructeur d'usine est factory. Nous savons que le constructeur inclut un constructeur de nom de classe et un constructeur nommé, factoryqui devient un constructeur d'usine après avoir été ajouté avant le constructeur. En d'autres termes factory, il peut être placé avant la fonction de nom de classe ou avant la fonction nommée.

Ci-dessous, nous passons Futurele constructeur d'usine pour créer le plus simple Future.

Comme vous pouvez le voir, Futurele constructeur d'usine reçoit une Dartfonction 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 Futurelorsque 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 Futurel'opération au cours de l' impression .

asyncEtawait

La valeur par défaut Futureest de s'exécuter de manière asynchrone. Si vous voulez notre Futureexécution synchrone, vous pouvez passer des mots async- awaitclés:

Comme vous pouvez le voir, le nôtre Futurea été exécuté de manière synchrone. awaitAttendra Futurela fin de l'exécution avant de continuer à exécuter le code suivant.

La asyncsomme des mots-clés awaitfait 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 Futureobjet.

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. awaitNe 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 queues'il contient des tâches et s'il y a des tâches, il sera exécuté jusqu'à ce que la microtask queuefile d'attente soit vide. Parce que microtask queuela priorité est la plus élevée. Ensuite, allez exécuter event queue. Généralement, les Futureévénements créés seront insérés et event queueexécutés dans l'ordre ( Future.microtasksauf pour la méthode d' utilisation ).

Remarque : Dans Dart, il ne async/awaits'agit que d'un sucre syntaxique, le compilateur ou l'interpréteur finira par le convertir en une Promise(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 asyncmots-clés, cela signifie que la testFuturefonction est devenue une fonction asynchrone.

Ainsi, testFuturel'impression après la fonction sera exécutée en premier .

 

Une fois l'impression terminée, il commencera à vérifier microtask queues'il contient des tâches et s'il y a des tâches, il sera exécuté jusqu'à ce que la microtask queuefile d'attente soit vide. Parce que microtask queuela priorité est la plus élevée. Ensuite, allez exécuter event queue. Généralement, les Futureévénements créés seront insérés et event queueexécutés dans l'ordre ( Future.microtasksauf pour la méthode d' utilisation ).

# Valeur future()

Créez-en un qui renvoie la valuevaleur 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.

FutureSimple à utiliser

# FutureRé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 Futurene correspondra qu'à un seul résultat, succès ou échec.

Veuillez garder à l'esprit que Futuretoutes les APIvaleurs de retour sont toujours un Futureobjet, de sorte que les appels en chaîne peuvent être effectués facilement .

DartLes trois méthodes suivantes sont fournies pour traiter Futureles 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 Futurerappel à 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  Futureexé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' Futureexécution est terminée, nous obtiendrons Futurela référence à cela , puis continuerons d'appeler la then()méthode. Alors, Dartcomment cette situation sera-t-elle gérée en ce moment? Dans ce cas, Dartle then()corps de méthode qui sera ajouté ultérieurement sera inséré microtask queueet exécuté dès que possible:

 

  1. Comme la testFuture()fonction est appelée en premier , elle est imprimée en premier future 13.

  2. Ensuite, effectuez l' testFuture()impression suivante.

  3. Démarrez l'exécution de la tâche asynchrone.

  4. Effectuez d'abord la microtask queuetâche la plus prioritaire scheduleMicrotask, imprimez future 12.

  5. Puis Futureexécutez à nouveau dans l'ordre de déclaration et imprimez future 1.

  6. Ensuite  futureFinish, imprimez future 2. L' futureFinishexécution est maintenant terminée. Donc, il Dartsera mis dans futureFinish la thenméthode qui sera appelée  plus tard microtask queue. En raison microtask queuede la plus haute priorité. Par conséquent  futureFinish , il  then sera exécuté en premier et imprimé  future 11.

  7. Continuez ensuite à exécuter à l' event queueintérieur future 3. Puis exécutez  thenet imprimez  future 4. Dans le même temps then, microtask queueune micro-tâche a été ajoutée à la méthode . Puisqu'il est en cours d'exécution à ce moment event 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  poursuivent  future 6. Cette boucle d'événements se termine et la boucle d'événements suivante prend  future 5 cette microtâche et l'imprime  future 5.

  8. microtask queueLa tâche est terminée. Continuez à effectuer event queueles tâches dans. Imprimer  future 7. Puis exécutez  then. Ce qu'il faut noter ici, c'est que le then retour à ce moment  est un retour nouvellement créé Future  . Donc ceci  thenet les suivants  then y seront ajoutés event queue.

  9. Continuez à effectuer evnet queueles tâches à l'intérieur dans l'ordre et imprimez  future 10.

  10. Dans la dernière boucle d'événements, retirez la méthode nouvellement ajoutée  evnet queuepassée à l'intérieur , et la suivante  , print.future 7thenfuture 8future 9

  11. L'ensemble du processus est terminé.

# Future.catchError

Enregistrer un rappel pour capturer Futurele error:

void testFuture() async {
  new Future.error('Future 发生错误啦!').catchError(print, test: (error) {
    return error is String;
  });
}

testFuture();

print("在testFuture()执行之后打印。");

Résultats du:

在testFuture()执行之后打印。
Future 发生错误啦!

thenRappel onErroretFuture.catchError

Future.catchErrorLe rappel ne gère que Futurel'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é Futureterminé après 2 s, mais il a été timeoutdéclaré expirer après 1 s, donc après 1 s, il Futurelancera 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 Futureachèvements et récupérez leurs résultats. Il existe deux situations:

 

Tous Futureont des résultats normaux renvoyés. Le Futurerésultat est le retour de tous les Futureensembles 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]

FutureUne erreur s'est produite dans un ou plusieurs d'entre eux et s'est produite error. Le Futurerésultat renvoyé est la première erreur de la Futurevaleur 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 Dartla boucle d'événements et event queueet microtask queue. Dans le même temps, Dart Futureune 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 Dartle fonctionnement asynchrone. Bien sûr, il existe des connaissances sur la Dartprogrammation 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 Futurele 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 syncla 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 queuecours d'exécution Future. Nous savons que cette microtask queuepriorité est event queueélevée. Le général Futureest en cours d' event queueexécution. Ainsi, celui Future.microtaskcréé Futureaura priorité sur les autres Futureexé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 Dartla boucle d'événements et event queueet microtask queue. Dans le même temps, Dart Futureune 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 Dartle fonctionnement asynchrone. Bien sûr, il existe des connaissances sur la Dartprogrammation asynchrone et le multi-threading, pas trop impliquées ici. Je continuerai à vous l'expliquer dans les articles suivants.

 

Je suppose que tu aimes

Origine blog.csdn.net/wangletiancsdn/article/details/106637055
conseillé
Classement