Retourner un futur à partir de sa propre fonction
Cette réponse est un résumé des nombreuses façons de procéder.
Point de départ
Votre méthode peut être n'importe quoi, mais pour les besoins de ces exemples, disons que votre méthode est la suivante :
int cubed(int a) {
return a * a * a;
}
Actuellement, vous pouvez utiliser votre méthode comme suit :
int myCubedInt = cubed(3); // 27
Cependant, vous souhaitez que votre méthode renvoie un Future
comme ceci :
Future<int> myFutureCubedInt = cubed(3);
Ou de pouvoir l'utiliser de manière plus pratique comme ceci :
int myCubedInt = await cubed(3);
Les solutions suivantes proposent toutes des moyens d'y parvenir.
Solution 1 : Constructeur Future()
La solution la plus simple consiste à utiliser le constructeur génératif de Future
.
Future<int> cubed(int a) {
return Future(() => a * a * a);
}
J'ai modifié le type de retour de la méthode en Future<int>
et a ensuite transmis le travail de l'ancienne fonction en tant que fonction anonyme à la fonction Future
constructeur.
Solution 2 : Constructeur nommé futur
Les contrats à terme peuvent se terminer par une valeur ou une erreur. Ainsi, si vous souhaitez spécifier explicitement l'une ou l'autre de ces options, vous pouvez utiliser l'option Future.value
o Future.error
des constructeurs nommés.
Future<int> cubed(int a) {
if (a < 0) {
return Future.error(ArgumentError("'a' must be positive."));
}
return Future.value(a * a * a);
}
Ne pas autoriser une valeur négative pour a
est un exemple inventé pour montrer l'utilisation de la fonction Future.error
constructeur. S'il n'y a rien qui puisse produire une erreur, vous pouvez simplement utiliser la fonction Future.value
comme suit :
Future<int> cubed(int a) {
return Future.value(a * a * a);
}
Solution 3 : méthode asynchrone
Un async
renvoie automatiquement un Future
vous pouvez donc simplement marquer la méthode async
et modifiez le type de retour comme suit :
Future<int> cubed(int a) async {
return a * a * a;
}
Normalement, vous utilisez async
en combinaison avec await
mais rien ne dit que vous devez le faire. Dart convertit automatiquement la valeur de retour en une valeur Future
.
Dans le cas où vous utilisez une autre API qui renvoie une valeur de Future
dans le corps de votre fonction, vous pouvez utiliser await
comme suit :
Future<int> cubed(int a) async {
return await cubedOnRemoteServer(a);
}
Ou bien c'est la même chose en utilisant l'option Future.then
syntaxe :
Future<int> cubed(int a) async {
return cubedOnRemoteServer(a).then((result) => result);
}
Solution 4 : Compléteur
L'utilisation d'un Completer
est la solution la plus simple. Elle n'est nécessaire que si vous avez une logique complexe que les solutions ci-dessus ne couvrent pas.
import 'dart:async';
Future<int> cubed(int a) async {
final completer = Completer();
if (a < 0) {
completer.completeError(ArgumentError("'a' must be positive."));
} else {
completer.complete(a * a * a);
}
return completer.future;
}
Cet exemple est similaire à la solution du constructeur nommé ci-dessus. Il gère les erreurs en complétant le futur de la manière habituelle.
Remarque sur le blocage de l'interface utilisateur
Rien dans l'utilisation d'un futur ne garantit que vous ne bloquerez pas l'interface utilisateur (c'est-à-dire l'isolat principal). Renvoyer un futur à partir de votre fonction indique simplement à Dart de planifier la tâche à la fin de l'isolat principal. file d'attente d'événements . Si cette tâche est intensive, elle bloquera toujours l'interface utilisateur lorsque la boucle d'événements en programmera l'exécution.
Si vous avez une tâche intensive que vous souhaitez exécuter sur un autre isolat, vous devez créer un nouvel isolat pour l'exécuter. Lorsque la tâche se termine sur l'autre isolat, elle renvoie un message en tant que futur, que vous pouvez transmettre en tant que résultat de votre fonction.
La plupart des classes d'IO standard de Dart (comme File
o HttpClient
) ont des méthodes qui délèguent le travail au système et n'effectuent donc pas leur travail intensif sur le fil d'exécution de l'interface utilisateur. Ainsi, les futurs renvoyés par ces méthodes ne risquent pas de bloquer votre interface utilisateur.
Voir aussi