web-dev-qa-db-fra.com

Obtention de valeurs à partir d'instances futures

Mes données ressemblent à ceci:

{
  "five": {
    "group": {
      "one": {
        "order": 2
      },
      "six": {
        "order": 1
      }
    },
    "name": "Filbert",
    "skill": "databases"
  },
  "four": {
    "group": {
      "three": {
        "order": 2
      },
      "two": {
        "order": 1
      }
    },
    "name": "Robert",
    "skill": "big data"
  },
  "one": {
    "name": "Bert",
    "skill": "data analysis"
  },
  "seven": {
    "name": "Colbert",
    "skill": "data fudging"
  },
  "six": {
    "name": "Ebert",
    "skill": "data loss"
  },
  "three": {
    "name": "Gilbert",
    "skill": "small data"
  },
  "two": {
    "name": "Albert",
    "skill": "non data"
  }
}

J'utilise la fonction suivante:

  Future retrieve(String id) async {
    Map employeeMap = await employeeById(id); //#1
    if (employeeMap.containsKey("group")) { //#2
      Map groupMap = employeeMap["group"];
      Map groupMapWithDetails = groupMembersWithDetails(groupMap); #3
      // above returns a Mamp with keys as expected but values 
      // are Future instances.
      // To extract values, the following function is
      // used with forEach on the map
      futureToVal(key, value) async { // #4
        groupMapWithDetails[key] = await value; 
      }
      groupMapWithDetails.forEach(futureToVal); // #4
    }
    return groupMapWithDetails;
   }
  1. J'accède à un employé (en tant que Map) à partir de la base de données (Firebase)
  2. Si l'employé est un leader (a un "groupe" clé)
  3. Je récupère les détails de chacun des employés du groupe à partir de la base de données en appelant une fonction distincte.
  4. Puisque la fonction renvoie une carte avec des valeurs qui sont des instances de Future, je veux en extraire les valeurs réelles. Pour cela, un forEach est appelé sur la carte. Cependant, je ne reçois que des instances de Future en tant que valeurs.

Comment puis-je obtenir les valeurs réelles?

7
Hesh

Il n'y a aucun moyen de revenir de l'exécution asynchrone à l'exécution synchronisée.

Pour obtenir une valeur à partir d'un Future, il existe deux façons

passer un rappel à then(...)

theFuture.then((val) {
  print(val);
});

ou utilisez async/await pour une syntaxe plus agréable

Future foo() async {
  var val = await theFuture;
  print(val);
}
26

Vous n'attendez pas le await value expressions à compléter.

L'appel forEach parcourt les entrées de mappage et démarre un calcul asynchrone pour chacune. L'avenir de ce calcul est alors abandonné car forEach n'utilise pas la valeur de retour de sa fonction. Ensuite, vous retournez la carte, bien avant la fin des calculs asynchrones, de sorte que les valeurs de la carte sont toujours des futurs. Ils finiront par devenir non-futurs, mais vous ne saurez pas quand cela sera fait.

Au lieu de l'appel forEach, essayez:

await Future.wait(groupMapWithDetails.keys.map((key) async {
  groupMapWithDetails[key] = await groupMapWithDetails[key];
});

Cela effectue une opération asynchrone pour chaque clé de la carte et attend que toutes se terminent. Après cela, la carte devrait avoir des valeurs non futures.

2
lrn