IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

Enchainement de promise dans foreach


Sujet :

JavaScript

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2011
    Messages
    278
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2011
    Messages : 278
    Points : 63
    Points
    63
    Par défaut Enchainement de promise dans foreach
    Bonjour à tous,

    j'essaye de comprendre le fonctionnement des promesses et ça met un sacré bordel dans ma tête

    Peut on m'expliquer pourquoi mon console.log(segId) renvoi vide a chaque fois alors qu'il est plein dans le then final?COmment faire pour tester une valeur dans un tableau dans des cas comme le miens ?
    Une solution plus simple serait de récupérer mes données dans 2 tableaux distinct (un tableau segment et un segment_effort) puis dans le then final

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
     
    async function getActivities(strava, accessToken)
    {
      const payload = await strava.athlete.listActivities({'access_token':accessToken, 'after':'1593899114','before':'1594763114', 'per_page':'10'})
      return payload;
    }
    async function getActivity(strava, accessToken, id)
    {
      const payload = await strava.activities.get({'access_token':accessToken, 'id':id, 'include_all_efforts':'true'})
      return payload;
    }
    async function getSegment(strava, accessToken, id)
    {
      const payload = await strava.segments.get({'access_token':accessToken,'id':id})
      return payload
    }
     
    getActivities(strava, accessToken).then(activities => {
      return Promise.all(activities.map(elem => {
          return getActivity(strava, accessToken, elem['id']).then(activity => {
              return Promise.all(activity['segment_efforts'].map(elem => {
                  console.log(segId)
                  if(segId.indexOf(elem['segment']['id']) == -1)
                  {
                    return getSegment(strava, accessToken, elem['segment']['id']).then(segment => {
                      segment.time = []
                      elem.segment = ""
                      segment.time.push(elem)
                      tableau.push(segment)
                      segId.push(segment['id']);
                    });
                  }else {
                    var index = segId.indexOf(elem['segment']['id']);
                    elem['segment'] = '';
                    tableau[index]['time'].push(elem)
     
                  }
              }));
          })
      }));
    })
    .then(_ => {
      console.log(segId)
    });
    merci d'avance

  2. #2
    Expert éminent
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 093
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 093
    Points : 6 754
    Points
    6 754
    Par défaut
    Bonjour,
    dans le code que tu montres, la variable segId n’est ni déclarée ni initialisée. Si tu utilisais le mode strict, l’accès à cette variable lèverait une erreur.

    Si je comprends bien ta structure, tu as un tableau d’activities, et chaque entrée a elle-même un tableau de 'segment_efforts', ce qui fait donc une structure à deux dimensions. C’est bien ça ?

    Attention aux valeurs de retour.
    Dans la branche if, tu as un getSegment().then, la fonction que tu passes à .then() n’a pas d’instruction return. La promesse renvoyée aura donc la valeur undefined.
    Idem dans la branche else, là tu ne renvoies carrément pas de promesse, et alors .map() comble le vide avec undefined dans le tableau résultat.

    Pour mieux voir ce qui se passe, tu peux séparer en plusieurs morceaux l’instruction Promise.all( … .map() ) : fais d’abord le .map(), fais un console.log() du résultat, puis passe-le à Promise.all().

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    const promises = activity['segment_efforts'].map(elem => {});
    console.log(promises);
    return Promise.all(promises);
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  3. #3
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2011
    Messages
    278
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2011
    Messages : 278
    Points : 63
    Points
    63
    Par défaut
    Bonjour Watilin,
    merci pour ce retour.

    La variable segId est declaré juste avant l'execution de la fonction getActivities (elle a sauté dans mon copié collé car en vrai j'ai pleins de ligne commenté qui était inutile ici ).

    Oui c'est bien ca pour la structure.
    Effectivement il y a pas de return. Cependant a la fin mes tableaux "tableau" et "segId" sont bien rempli comme je le souhaite. Pour le else j'avais vu ça après avoir assimilé ce que fais map...

    Pour expliquer ma problématique:
    Je récupère mes données via l'API strava (réseau social de sport ou sont enregistré toutes mes sorties vélo). Cette API limite les accès pour les comptes gratuit, je veux donc limiter mes appels
    Dans ma BD un segment est unique. Donc quand je récupère les segment_effort (qui contiennent l'id du segment) je veux tester si je possède ce segment pour ne pas faire d'appel inutile à l'API.

    le tableau retourné par map est vide ...
    C'est donc impossible de faire du traitement de donnéés dans une promesse ?
    Je suis absolument perdu dans l'ordre d'execution de ce que je fais ...

  4. #4
    Expert éminent
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 093
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 093
    Points : 6 754
    Points
    6 754
    Par défaut
    Citation Envoyé par alex8276 Voir le message
    le tableau retourné par map est vide ...
    Que veux-tu dire précisement ? Le tableau a-t-il zéro éléments, ou contient-il des éléments avec une valeur « falsy » comme undefined ou null ?
    En principe map conserve le nombre d’éléments, donc si tu as zéro éléments c’est que l’API t’a fourni un tableau vide.

    C'est donc impossible de faire du traitement de donnéés dans une promesse ?
    Je suis absolument perdu dans l'ordre d'execution de ce que je fais ...
    Avec les promesses il faut avoir un « déclic » pour comprendre, sois patient, ça finira par arriver Voici quelques petites explications pour t’aider.

    Promise.all attend un tableau de promesses, mais pour être plus souple il accepte aussi dans le tableau des valeurs non-promesses, et les considère comme des promesses déjà résolues. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Promise.all([
      new Promise((resolve, reject) => {
        setTimeout(() => { resolve("promesse à 1 seconde"); }, 1000);
      }),
      "du texte",
      42
    ])
    .then((tableau) => {
      console.log(tableau);
    });
    La fonction Promise.all renvoie une promesse, tu l’as sans doute remarqué. C’est la raison pour laquelle tu peux enchaîner avec .then(). La promesse renvoyée est résolue quand toutes les promesses du tableau ont été résolues.

    Quand tu imbriques des Promise.all, la résolution va du plus profond vers la surface : il faut d’abord que les promesses du Promise.all le plus imbriqué soient toutes résolues, pour permettre de résoudre le Promise.all du niveau d’au-dessus.

    Les .then() dans ton code marquent des « points de sortie » dans l’exécution du code, les endroits où du code asynchrone est mis en attente pour être exécuté plus tard. Note que les appels à .map() sont synchrones, et donc s’exécutent avant tout code mis en attente. En réécrivant les instructions comme je t’ai montré dans mon post précédent, tu comprendras sans doute mieux à quel chemin l’exécution suit dans ton code.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    getActivities(strava, accessToken).then(activities => {
      const resultatMapExterieur = activities.map(elem => {
        // premier .then(), la fonction passée est mise en attente
        // puis l’itération se termine et .map() passe à l’itération suivante
        return getActivity(strava, accessToken, elem['id']).then(activity => {
     
          const resultatMapInterieur = activity['segment_efforts'].map(elem => {
            ...
            ...
          });
     
          return Promise.all(resultatMapInterieur);
        });
      });
     
      // à ce point, le .map() a complété de manière synchrone, aucun .then() n’a encore été rappelé
      // resultatMapExterieur contient donc des promesses qui seront résolues plus tard
      return Promise.all(resultatMapExterieur);
    })
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  5. #5
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2011
    Messages
    278
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2011
    Messages : 278
    Points : 63
    Points
    63
    Par défaut
    Bonjour,
    Que veux-tu dire précisement ? Le tableau a-t-il zéro éléments, ou contient-il des éléments avec une valeur « falsy » comme undefined ou null ?
    En principe map conserve le nombre d’éléments, donc si tu as zéro éléments c’est que l’API t’a fourni un tableau vide.
    bon je rectifie j'ai bien un tableau de promesse qui est retourné par mon.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    const promises = activity['segment_efforts'].map(elem => {});
    j'avais un comportement bizarre hier a un moment ... Les données n'était plus récupérés et j'avais pas de message d'erreur. Bref.

    Merci pour ces explications qui m'éclaircissent un peu en attendant d'avoir le fameux déclic ! Je vais etudier ce bout de code !

Discussions similaires

  1. Perl et Mysql soucis dans foreach
    Par dycobe dans le forum Langage
    Réponses: 5
    Dernier message: 16/05/2007, 15h54
  2. Enchainement de requête dans une même procedure stockée
    Par dahu17 dans le forum Langage SQL
    Réponses: 5
    Dernier message: 25/04/2007, 11h22
  3. [PHP-JS] for dans foreach
    Par Invité dans le forum Langage
    Réponses: 2
    Dernier message: 28/12/2006, 18h31
  4. Problème d'enchainement de fichiers dans iFrame
    Par mathieugamin dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 19/10/2006, 16h06
  5. Enchainer des fonctions dans un onclick d'un bouton
    Par jpg dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 26/10/2004, 16h51

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo