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 :

[Promise All] Récupérer résultat


Sujet :

JavaScript

  1. #1
    Membre éclairé
    Homme Profil pro
    Symfony - CMS Wordpress - Zend
    Inscrit en
    Septembre 2011
    Messages
    306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Symfony - CMS Wordpress - Zend
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2011
    Messages : 306
    Par défaut [Promise All] Récupérer résultat
    Bonjour,

    Concernant les Promesse en JS, je doit setter la ou les valeur(s) dans une MAP(clé,valeur).

    Seulement je n'ai pas mon tableau entier :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Map {
      'Startpage' => Map { 'TranslationsSubSections' => Map {} },
      'Aboutpage' => Map {} }
    voici la promesses:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    let test = Promise.all([getTranslation(key, value)]);
                    test.then(function (result) {
     
                        myArrayArray.set(key,result);
     
                    });
    quand je veux stocker le resultat dans une variable depuis la promesse je recupere un undefined.

    et quand ma variable est dans ma promesse et que je veux y acceder depuis l'exterieur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    let test = Promise.all([getTranslation(value, lang)]);
                    test.then(function (result) {
                        mymap = result;
                    });
     
                    translatedArray.set(key,mymap);
    j'ai ce resultat:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Map {
      'Title' => undefined,
      'Intro' => undefined,
      'Startpage' => Map {
      'TranslationSections' => undefined,
      'TranslationsSubSections' => Map {
      'TitleOne' => undefined,
      'TitleTwo' => undefined,
      'TitleTree' => undefined } },
      'Aboutpage' => Map { 'TranslationSections' => undefined } }
    mon tableau avant traitement:

    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
    {
      "Title": "Translation example",
      "Intro": "Hello I am et, I am 500 years old.",
      "Startpage": {
        "TranslationSections": "Hello World",
        "TranslationsSubSections" :{
          "TitleOne"  : "Hello All",
          "TitleTwo"  : "Hello You",
          "TitleTree" : "Hello Me"
        }
      },
      "Aboutpage": {
        "TranslationSections": "We are letsboot"
      }
    }
    quand j'essaie de stoker les valeurs de ma promesses dans un tableau

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    let test = Promise.all([getTranslation(value, key)]);
                    test.then(function (result) {
                        mymap[key] = result;
                    });
    j'ai cette erreur..:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (node:1562) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Cannot set property 'TitleOne' of undefined
    Je touche au but mais j'ai un manque de compréhension envert le fonctionnement des promesses.

    Merci pour votre aide.

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

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Par défaut
    Salut,

    comment ça va depuis hier ?

    Bon, j’essaye de comprendre la logique de ton code mais je pense qu’il manque des éléments. Je vais essayer de t’aider quand même.

    Je reconnais que je ne t’ai pas donné beaucoup d’indications la dernière fois. Promise.all attend en paramètre un tableau d’objets Promise, et renvoie une nouvelle promesse qui est résolue si et seulement si toutes les promesses du tableau sont résolues. Mais voyons ce qui se passe dans ton code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    let test = Promise.all([ getValues(key, value) ]);
    Tu passes un tableau à Promise.all, mais je ne sais pas ce que renvoie getValues. Cette fonction renvoie-t-elle une promesse ? Un tableau de promesses ? Je pense qu’il y a un niveau de tableau en trop.
    • Soit getValues renvoie une seule promesse, et dans ce cas tu n’as pas besoin de Promise.all ;
    • soit elle renvoie déjà un tableau, et dans ce cas tu n’as pas besoin des crochets [ ... ].


    Note : si le tableau passé à Promise.all contient autre chose que des promesses, ça va marcher quand même (en tout cas sous Firefox, je viens de tester), et ça va considérer que tu as passé des promesses déjà résolues. Mais c’est un peu « par accident » et je ne crois pas que ce soit une bonne idée de se reposer sur ce comportement.

    Je ne sais pas si ça va t’aider, mais j’ai lu récemment un article de blog qui proposait de transformer la fonction setTimeout en quelque chose qui retourne une promesse. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    timeout(1000).then(() => { console.log("bonsoir"); });
    À ton avis, comment on s’y prend ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    let timeout = (delay) => {
      return new Promise((resolve, reject) => {
        // ???
      });
    }
    Réponse :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    let timeout = (delay) => {
      return new Promise((resolve, reject) => {
        setTimeout(resolve, delay);
      });
    }
    Note qu’on n’utilise pas reject : jusqu’à preuve du contraire, un setTimeout n’échoue jamais.


    À présent on va utiliser un tableau de promesses contenant des timeouts de différents délais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    let timeouts = [ timeout(1000), timeout(500), timeout(777), timeout(1500) ];
    Dans ta console, tu peux vérifier le « type » (en fait, le prototype) des promesses en utilisant Object.getPrototypeOf
    Code console : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    >> Object.getPrototypeOf(timeouts[3])
    << PromiseProto { ... }

    Maintenant, si on veut attendre que tous les délais soient écoulés, on passe le tableau timeouts à Promise.all :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Promise.all(timeouts).then((something) => { console.log(something); });
    Dans le cas présent, la console affichera un tableau contenant quatre fois undefined, qui s’explique par le fait qu’on avait quatre promesses dans le tableau de départ, et que ces promesses ne se résolvent en aucune valeur.




    Tu trouveras peut-être que cet exemple n’était pas très parlant. Prenons un autre cas simple : des promesses qui se résolvent instantanément (mais attention, une promesse se résoud toujours de manière asynchrone !)
    Encore une fois, je te laisse l’exercice avec la réponse en spoiler. On veut quelque chose qui se comporte comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    promise42.then((value) => { console.log(value); }); // affiche 42
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    let promise42 = new Promise((resolve, reject) => { resolve(42); });


    On peut corser un tout petit peu les choses en souhaitant quelque chose de plus dynamique : une fonction qui reçoit un paramètre et qui retourne une promesse qui se résoud en ce paramètre.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    promiseNumber(42).then((value) => { console.log(value); }); // affiche 42
    Ce n’est pas plus difficile que timeout.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    let promiseNumber = (number) => {
      return new Promise((resolve, reject) => {
        resolve(number);
      });
    };


    Construisons à nouveau un tableau de promesses, et passons-le à Promise.all :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    let promiseNumbers = [ promiseNumber(42), promiseNumber(187), promiseNumber(5) ];
     
    Promise.all(promiseNumbers).then((array) => {
      array.forEach((value) => { console.log(value); });
    });



    Un peu plus haut, j’ai rapidement attiré ton attention sur le fait que les promesses se résolvent toujours de façon asynchrone. C’est une manière savante de dire « pas dans l’ordre ». Tu auras sans doute remarqué ce genre de phénomène :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    new Promise((resolve, reject) => {
      resolve("Haricot");
    }).then((value) => { console.log(value); });
     
    console.log("Patate");
    « Patate » s’affichera toujours avant « Haricot », et ce n’est pas un hasard : les promesses ont été conçues de cette façon.

    Si tu tentes de traiter des données en dehors d’un .then, ton traitement se fera sur des données qui ne sont pas prêtes. Concrètement, quand tu fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    test.then(function (result) {
      mymap = result;
    });
     
    translatedArray.set(key, mymap);
    mymap n’est pas prêt au moment où tu le passes à translatedArray.set. Si tu fais l’opération à l’intérieur de la fonction .then, ça devrait marcher.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    test.then(function (result) {
      mymap = result;
      translatedArray.set(key, mymap);
    });
    Une autre façon de faire : si tu utilises un return (ou la forme « expression » des fonctions flèches) à l’intérieur d’une fonction .then, tu peux chaîner les .then :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    new Promise((resolve, reject) => resolve(42))
    .then((value) => { return value * 2; })
    .then((value) => value + 1)
    .then((value) => { console.log(value); });
    Et là, les choses se feront dans l’ordre que tu souhaites.
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  3. #3
    Membre éclairé
    Homme Profil pro
    Symfony - CMS Wordpress - Zend
    Inscrit en
    Septembre 2011
    Messages
    306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Symfony - CMS Wordpress - Zend
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2011
    Messages : 306
    Par défaut
    Merci pour ton aide.

    En effet ma fonction ne retourne pas un tableaux de promesses un unique resultat à la fois:

    Ma fonction est fait: getValues -> getTranslation

    Voici ma fonction :

    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
    function getTranslation(input, key) {
     
        var promise = new Promise((resolve, reject) => {
          https.get(options, (result) => {
            let body = '';
     
            result.on('data', (chunk) => {
                body += toUTF8(chunk);
            });
     
            result.on('end', () => {
                resolve(result.toLowerCase());
            });
        }).on('error', (e) => {
             reject();
     
        })});
        return promise;
    }
    et ma fonction de retour:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    let test = getTranslation(key, value)
                 .then((value) => {
               translatedArray.set(key,value)
    });
    et voici ma fonction d'appel:

    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
    function mytest(array, lang)
    {
       var valuesArray = new Map();
       array.forEach(function(value,key) {
               if (value instanceof Object) {
                valuesArray.set(key, mytest(value, lang));
                console.log("inside an object map");
            }
            else {
     
                Promise.all(getTranslation(key, value))
                    .then((value) => {
                        translatedArray.set(key, value)
                    });
            }
        });
        return valuesArray;
    }

    je recupère une partie de mon tableau comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Map {
      'Startpage' => Map { 'TranslationsSubSections' => Map {} },
      'Aboutpage' => Map {} }
    Pas le tableau integral..

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

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Par défaut
    J’ai l’impression que tu as deux variables dans ta fonction mytest qui remplissent le même rôle : valuesArray et translatedArray. À mon avis tu devrais retirer une des deux.

    Pour le reste, je pense que tu n’es pas loin d’avoir quelque chose qui marche. Et je crois qu’en fin de compte, tu n’auras pas besoin de Promise.all. En fait, Promise.all pourrait même te poser problème car, vu que tu fais un certain nombre de requêtes réseau, il y a une certaine probabilité qu’au moins une d’entre elles échoue, et donc que Promise.all renvoie un résultat négatif. Malheureusement, il n’existe pas de fonction native Promise.most qui permettrait de ne pas tenir compte des échecs… Cela dit, rien ne nous empêche de la coder nous-mêmes.

    Attention aux noms que tu donnes à tes arguments de fonctions. Il y a un manque de cohérence entre cette ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    function getTranslation(input, key) {
      ...
    Et celle-ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    getTranslation(key, value) ...
    Également, la variable body dans getTranslation n’est pas utilisée à la fin. J’imagine que c’est un oubli.

    Un détail à propos de ta fonction récursive : à l’intérieur tu appelles un forEach. Je ne sais pas quelle profondeur peut atteindre ta structure de données, mais j’ai déjà vu certains scripts échouer à cause de la pile d’appels qui était surchargée. Dans ton cas tu peux limiter ce risque en remplaçant la fonction forEach par une boucle for..of combinée à Object.entries :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
       ...
       var valuesArray = new Map();
       for (let [ key, value ] of Object.entries(array)) {
          ...
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  5. #5
    Membre éclairé
    Homme Profil pro
    Symfony - CMS Wordpress - Zend
    Inscrit en
    Septembre 2011
    Messages
    306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Symfony - CMS Wordpress - Zend
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2011
    Messages : 306
    Par défaut Encore un petit effort avant de trouvé..
    Je reprend ou j'en suis maintenant:

    je mon promisse All comme ce-ci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    function sendToGoogleTranslate(array, lang) {
     
        if (array && array.size > 0) {
            let myloop = mytest(array,lang);
            Promise.all(myloop).then(function(promises){
                console.log("Arriver en dernier");
            });
        }
    }
    Normalement je doit avoir mes promisse avant mon log?
    ou je me trompe ? Je commence seulement a comprendre

    voici mes promisses:

    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
     
    function doSometing(translatedArray,result,key){
        return new Promise((resolve) => {
            setTimeout(() =>{
                resolve(translatedArray.set(key,result));
            },1000)
        } ).then((value) => console.log("dosometings -> " + key));
    }
     
    function mytest(array, lang)
    {
        var translatedArray = new Map();
        let promise = [];
        array.forEach(function(value,key) {
                if (value instanceof Object) {
                    translatedArray.set(key, mytest(value, lang));
                    console.log("inside an object map");
                }
                else {
                    getTranslation(value, lang, (result) => {
                       promise.push(doSometing(translatedArray,result,key));
                    });
                    console.log(" value befor do someting"+value);
                }
            });
        return promise;
    }
    voici mon resultat:

    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
    Arriver en dernier
    Arriver en dernier
    Arriver en dernier
    dosometings -> TranslationSections
    dosometings -> TitleTwo
    dosometings -> TranslationSections
    dosometings -> Intro
    dosometings -> TranslationSections
    dosometings -> Title
    dosometings -> TranslationSections
    dosometings -> TranslationSections
    dosometings -> TitleTwo
    dosometings -> Title
    dosometings -> TitleTree
    dosometings -> Intro
    dosometings -> TitleTree
    dosometings -> TranslationSections
    dosometings -> TitleOne
    dosometings -> Title
    dosometings -> Intro
    dosometings -> TitleOne
    dosometings -> TitleOne
    dosometings -> TitleTwo
    dosometings -> TitleTree
    Le resultat des promisses viens au fur et mesure et du coup mon message en console
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    console.log("Arriver en dernier");
    devrait venir en dernier..

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

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Par défaut
    Citation Envoyé par sinzen Voir le message
    Le resultat des promisses viens au fur et mesure et du coup mon message en console
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    console.log("Arriver en dernier");
    devrait venir en dernier..
    Il viendrait en dernier si tu n’avais pas demandé un setTimeout d’une seconde… Une seconde c’est énorme en comparaison du temps d’exécution d’une fonction JavaScript moyenne, même récursive. Tu peux t’en rendre compte en plaçant des performance.now() avant et après l’appel à mytest :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        function sendToGoogleTranslate(array, lang) {
          if (array && array.size > 0) {
     
            let t0 = performance.now();
            let myloop = mytest(array, lang);
            let t1 = performance.now();
            console.log(t1 - t0); // affiche des millisecondes
     
            Promise.all(myloop).then(function (promises) {
              console.log("Arriver en dernier");
            });
          }
        }
    Je suis à peu près certain que ça t’affichera un nombre qui est largement inférieur à 1000.

    Je pense qu’il te manque la compréhension de ce qui est synchrone et ce qui ne l’est pas.

    Une résolution de promesse est asynchrone.
    Une fonction appelée avec setTimeout, setInterval ou requestAnimationFrame est asynchrone.
    Un gestionnaire d’évènement, ce qui inclut les évènements ajax mais aussi les évènements souris/tactile et clavier, est asynchrone.
    Un appel récursif, une boucle for ou while, une création d’objet, tout ça est synchrone.
    Généralement, tout le reste est synchrone, mais il y a peut-être des cas que j’ai oubliés.

    Sous les navigateurs actuels, (si on oublie la récente technologie des workers) JavaScript n’a qu’un seul fil (thread) d’exécution. Le code asynchrone est placé en attente, et est exécuté immédiatement dès que le thread est libre.

    Imagine une fonction simple contenant uniquement des instructions synchrones :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function f() {
      let x = 5;
      x = x * 2;
      x = x + 1;
      console.log(x);
    }
    Cette fonction peut être visualisée comme un bloc indivisible sur le thread JavaScript :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
            thread
              |
              |
           +-----+
           |     |
           | f() |
           |     |
           +-----+
              |
              |
    Maintenant, imagine que nous plaçons une promesse dans cette fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    function f() {
      let x = 5;
      x = x * 2;
      x = x + 1;
      Promise.resolve("coucou")
        .then(function g(value) { console.log(value); });
      console.log(x);
    }
    La fonction que nous passons à .then, que j’ai nommée g pour plus de lisibilité, est placée en file d’attente jusqu’à ce que le thread soit libéré. En l’occurence, quand la fonction f() se termine.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
            thread
              |
           +-----+
           |     |   .then()       file d’attente
           | f() ---------------> { g() }
           |     |                   |
           +-----+                   |
           +-----+ <-----------------/
           |     |
           | g() |
           |     |
           +-----+
              |
    On peut voir que, en quelques sortes, un nouveau bloc a été « sorti » du bloc principal. Et on voit bien que la valeur de x (11) va s’afficher avant le « coucou ».

    Quand tu utilises setTimeout, un délai est rajouté artificiellement pour retarder l’exécution de la fonction.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function f() {
      let x = 5;
      x = x * 2;
      x = x + 1;
      setTimeout(function g() {
        console.log("bonne nuit");
      }, 1000);
      console.log(x);
    }
    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
            thread
              |
           +-----+
           |     |   setTimeout(g, délai)     file d’attente
           | f() --------------------------> { g() }
           |     |                             |
           +-----+                             |
              |                                | + délai
              ~                                |
              ~                                |
              |                                |
           +-----+ <---------------------------/
           |     |
           | g() |
           |     |
           +-----+
              |
    Tout ça pour dire que je ne comprends pas pourquoi tu as voulu mettre un setTimeout dans ta promesse. Est-ce que je t’ai induit en erreur avec mes explications précédentes ?
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  7. #7
    Membre éclairé
    Homme Profil pro
    Symfony - CMS Wordpress - Zend
    Inscrit en
    Septembre 2011
    Messages
    306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Symfony - CMS Wordpress - Zend
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2011
    Messages : 306
    Par défaut J’ai réalisé des séquences de test..
    Comme tu a dit si élégamment,
    J'ai du mal à comprendre ce qui est synchrone ou pas.
    Je vais travailler sur cela dès que j'ai le temps.

    Pour ce qui est du code,

    1. Le timeout n'a rien à faire la
    2. Je récupère bien les promesses après mon log


    Je te remercie pour tes explications.

    Mais pour finir en beauté,
    Maintenant je dois reconstruire ma structure en objet
    Avec couple clés et valeurs.
    Ma question est la suivante :
    • J'ai la clé
    • J'ai la valeur
    • Et fais un push dans mon tableau


    Seulement mes couples ne sont pas ensemble.
    Je veux dire est-ce c'est possible d'utiliser un Map()?
    Ou un objet à la place du tableau de promesses ?

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

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Par défaut
    Re,

    il me manque encore des éléments pour avoir une compréhension globale de ton code. Par exemple, je ne sais pas ce que fait getTranslation, et je ne sais pas à quel moment sendToGoogleTranslate est appelée.

    Attention également à ne pas confondre array et map, les deux existent en JS et ont un fonctionnement différent.
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

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

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Par défaut
    Et bonsoir !

    Je n’avais pas vu ton message de 18h13, excuse-moi si ma dernière réponse a paru à côté de la plaque.

    Si le code que tu as donné la dernière fois est toujours d’actualité, j’ai une petite remarque :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    function doSometing(translatedArray,result,key){
        return new Promise((resolve) => {
            setTimeout(() =>{
                resolve(translatedArray.set(key,result));
            },1000)
        } ).then((value) => console.log("dosometings -> " + key));
    }
    Un truc à bien comprendre c’est que chaque appel à .then renvoie une nouvelle promesse, et cette promesse prend pour valeur ce qui est retourné par la fonction passée en paramètre. En clair :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    let p1 = new Promise( ... );
    let p2 = p1.then((value) => { return 42; });
    let p3 = p2.then( ... );
    p1, p2 et p3 sont trois promesses différentes. p2 se résoud avec la valeur 42 car c’est ce qui est renvoyé par la fonction passée à l’appel .then qui la crée. J’espère que ce n’est pas trop confus

    Dans ton cas,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        return new Promise(
            ...
        ).then((value) => console.log( ... ));
    Ce qui est retourné ici est une promesse, pas celle créée par new Promise mais celle qui est créée par .then. On vient de le voir, ce sont deux promesses différentes. Cette dernière promesse se résoud avec la valeur renvoyée par console.log. Or, console.log renvoie toujours undefined… Tu obtiens donc, au final, une promesse qui se résoud avec undefined pour valeur. Ajoute un return value pour joindre les deux bouts.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        ...
        ).then((value) => {
            console.log("dosometings -> " + key);
            return value;
        });

    Pour finir, je reviens sur le tableau avant traitement que tu as donné en début de topic :
    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
    {
      "Title": "Translation example",
      "Intro": "Hello I am et, I am 500 years old.",
      "Startpage": {
        "TranslationSections": "Hello World",
        "TranslationsSubSections" :{
          "TitleOne"  : "Hello All",
          "TitleTwo"  : "Hello You",
          "TitleTree" : "Hello Me"
        }
      },
      "Aboutpage": {
        "TranslationSections": "We are letsboot"
      }
    }
    Techniquement, ce n’est pas un tableau. Ce n’est pas non plus une Map – ou alors c’en est une mais tu ne l’as pas écrite de la même façon que les autres maps que tu montres.

    Dans tous les cas, si ce n’était ni un tableau ni une map, il n’aurait pas de méthode forEach et tu ne pourrais pas le passer tel quel à ta fonction récursive. Ce qui me fait me poser la question : qu’est-ce que tu passes en réalité à mytest ? Quelle est la valeur initiale de ce paramètre array ?

    Note que tester if (value instanceof Object) ne garantit pas que l’objet en question aura la méthode forEach. Actuellement, cette partie de ton code marche par accident. Tu rendras ce test plus robuste en remplaçant Object par Array ou Map, selon quel est le vrai type de ton argument.
    Sinon, de manière plus pragmatique, tu pourrais simplement tester la présence de la méthode forEach :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if ("forEach" in value)
    … Ou encore vérifier que l’objet est itérable :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (Symbol.iterator in value)
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  10. #10
    Membre éclairé
    Homme Profil pro
    Symfony - CMS Wordpress - Zend
    Inscrit en
    Septembre 2011
    Messages
    306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Symfony - CMS Wordpress - Zend
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2011
    Messages : 306
    Par défaut Resultat des promises = un tableau
    Bonsoir Watilin,

    ma fonction retourne bien mon resultat sous forme d'un tableau de resultats.

    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
     
    function sendToGoogleTranslate(array, lang) {
     
        if (array && array.size > 0) {
            let myloop = mytest(array,lang);
     
            Promise.all(myloop)
                // .then(function(promises){
                // writeToJsonFile(lang, promises);
            // })
            .then((promises) => {
                promises.forEach((value) => {
                    console.log("key => "+value);
                });
            });
        }
    }
    cette fonction est appelé dans cette boucle afin de passe le(s) fichier(s) Json et le transposer en structure clés valeurs Map.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    langsToTranslate.forEach( (value, key) => {
     
                sendToGoogleTranslate(value, key);
     
        });
    et langToTranslate içi:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     
    fs.readdirSync(assetsFolder).forEach(file => {
    ...
    let map = new Map(transformToArrayKeyValue(parsedJSON));
     
    langsToTranslate.set(key, map);
    });
    Voici mon cas que je voudrai réaliser:

    • Utiliser le tableau de promesse resultat escompté
    • et reconstruire une structure clés valeurs (MAP)
    • et le transformer en objet pour fournir un fichier Json


    voici ma structure du tableau de promesses:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    TRANSLATED WORD (fr)  [ 'exemple de traduction',
      'bonjour je suis et, j\'ai 500 ans.',
      'bonjour le monde',
      'bonjour à tous',
      'salut toi',
      'bonjour moi',
      'nous sommes letsboot' ]

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

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Par défaut
    Je dois préciser que je n’avais pas compris jusqu’à maintenant que tu étais côté serveur. Mais ça ne change pas grand chose.

    Juste pour être bien clair, je voudrais insister sur la différence entre Array et Map. Les deux ont une méthode forEach, mais le nombre d’éléments se mesure avec length pour les arrays, et size pour les maps. Un array n’a pas de méthode set et ne devrait être utilisé qu’avec des index numériques. Les maps ont été ajoutées au langage, entre autres, pour pallier un manque de fonctionnalité qui faisait que les développeurs utilisaient des chaînes comme index d’arrays et avaient des problèmes à cause de ça.

    Note que j’ai fait exprès de ne pas utiliser le mot « tableau » dans le paragraphe précédent. Pour moi, tableau signifie Array, mais j’ai l’impression que tu l’utilises de manière interchangeable pour Array et Map.

    Tu admettras que l’écriture array.size prête à confusion. Malgré ça je suis à peu près convaincu que tu es capable de bien faire la distinction, et que c’est juste le nom de la variable qui est inapproprié.


    Ok ok, on discute terminologie et on ne fait pas avancer le schmilblick.

    Il y a un problème assez subtil avec Promise.all dans ton code actuel, et je vais essayer de te l’expliquer à travers ce petit exemple.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    let resolveP;
     
    let p = new Promise((resolve, reject) => {
      resolveP = resolve;
    });
     
    Promise.all([ Promise.resolve(42), p, "un truc au pif" ])
    .then((values) => {
      values.forEach((v) => { console.log(v); });
      return values;
    });
    J’ai préparé un Promise.all qui reçoit un tableau de trois éléments. Le premier élément est une promesse déjà résolue, elle a 42 pour valeur. Le troisième élément est une valeur primitive, une chaîne. Il est important de noter que ce n’est pas une promesse, mais la fonction Promise.all est tolérante et la considère comme une promesse résolue.

    Le deuxième élément, p, est une promesse, que j’ai créée juste avant, qui n’est pas encore résolue. Ce sera le déclencheur. Pour la résoudre au moment voulu, j’ai fait sortir la fonction resolve de sa portée locale en l’assignant à une variable extérieure, resolveP.

    Au moment où on va appeler resolveP, on va donc résoudre p, et du même coup le Promise.all dont tous les autres éléments sont déjà résolus.

    La console affiche ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    42
    817
    un truc au pif
    Les deux trucs qu’on constate rapidement sont :
    • Les choses se font dans l’ordre dans lequel on a passé les choses à Promise.all ;
    • La fonction de .then reçoit des valeurs directes et pas des promesses.


    La chose moins évidente, mais celle qui est importante dans notre situation, c’est que Promise.all accepte des valeurs qui ne sont pas des promesses, et les considère comme des promesses résolues. Ça implique que si tu lui passes uniquement des non-promesses, la promesse résultante va se résoudre instantanément.

    Certes, ta fonction mytest renvoie un tableau (array), mais si j’en crois ce que tu me montres :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    TRANSLATED WORD (fr)  [ 'exemple de traduction',
      'bonjour je suis et, j\'ai 500 ans.',
      'bonjour le monde',
      'bonjour à tous',
      'salut toi',
      'bonjour moi',
      'nous sommes letsboot' ]
    ce n’est pas un tableau de promesses, c’est simplement un tableau de chaînes. mytest utilise des promesses en interne, mais le reste de ton script ne le sait pas. Et comme Promise.all se résoud immédiatement, tes données ne sont pas prêtes quand la fonction du .then est appelée.


    Fais bien attention à la valeur de retour de ta fonction récursive mytest.

    Dans l’appel initial let myloop = mytest(array, lang);, tu l’utilises avec l’intention de récupérer un tableau de promesses.
    Dans l’appel récursif translatedArray.set(key, mytest(value, lang));, ton intention est de récupérer les données directement.

    Il me semble que ces deux usages sont en conflit.

    Classiquement, quand on fait de la programmation récursive, l’information peut circuler dans deux sens : vers le bas (par les paramètres) ou vers le haut (par valeur de retour). On a aussi la troisième voie : utiliser une variable extérieure. Il me semble que c’est ce que tu faisais dans une version précédente de ton code.

    Voici mon conseil :
    • ne change rien aux paramètres,
    • utilise une variable extérieure (je propose translationsMap) pour stocker les données,
    • sers-toi de la valeur de retour pour faire remonter les promesses.

    N’oublie pas de gérer ces transferts d’informations dans toutes les branches if/else de la fonction.

    Quand toutes les promesses sont résolues, si tu les as toutes fait remonter correctement, Promise.all se résoud alors, et tu sais qu’à ce moment tu peux utiliser les données présentes dans translationsMap.

    Le récursif c’est toujours un peu magique, mais relie bien les tuyaux et ça devrait bien se passer

    Après ça on essayera de coder une variante de Promise.all qui tolère les échecs de requêtes.
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  12. #12
    Membre éclairé
    Homme Profil pro
    Symfony - CMS Wordpress - Zend
    Inscrit en
    Septembre 2011
    Messages
    306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Symfony - CMS Wordpress - Zend
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2011
    Messages : 306
    Par défaut Traduction injecter dans ma structure.
    J'ai trouve un solution qui marche mais reste a savoir si c'est correct.

    J'ai bien un tableau de Promesse que je recupere de mes requete HTTP.

    Ma structure Map est dans un certain ordre a ne pas changer.

    Car mon tableau de promesse est dans le même ordre.

    Je fait un recursion sur ma structure Map et injecte le premièr element de la pile.

    Ensuite je depile au fur et a mesure dans l'iteration de ma Map:

    Voici ce que je fait:

    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
     
    function myfunctionForTranslate(translatedMap,promises){
        let myPromises = promises;
        translatedMap.forEach((value,key) => {
            if(typeof value === 'object')
            {
                translatedMap.set(key,myfunctionForTranslate(value,myPromises));
                console.log("in object => " + key);
            }
            else
            {
                translatedMap.set(key,myPromises[0]);
                myPromises.shift();
            }
        });
        return translatedMap;
    }
    j'attend ton avis..

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

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Par défaut
    Eh bien, je ne vois pas de bug flagrant et les arguments et retours ont l’air de correspondre aux types attendus. Du coup, je ne vois pas trop pourquoi tu attends mon avis. Il reste à améliorer ce test typeof ... === 'object', mais ce n’est pas prioritaire.

    Tu dis que tu as une « solution qui marche », ça veut dire quoi exactement ? Tu arrives à récupérer la map avec toutes les traductions ?
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  14. #14
    Membre éclairé
    Homme Profil pro
    Symfony - CMS Wordpress - Zend
    Inscrit en
    Septembre 2011
    Messages
    306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Symfony - CMS Wordpress - Zend
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2011
    Messages : 306
    Par défaut Merci..
    Oui bien,

    Je récupère ma Map et j'injecte les traductions quand mes promesses sont résolu..

    Je part du fait qu'il y a toujours une solutions meilleurs.

    Mais dans mon cas grâce a toi, c'est la solutions que j'ai trouvé..

    Merci a toi Watilin. passe une bonne semaine.

    Je mets le post en résolu.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Récupérer résultat d'une requête
    Par nerila dans le forum Bases de données
    Réponses: 10
    Dernier message: 02/03/2007, 12h53
  2. Récupérer résultat d'une rotation
    Par Burckel dans le forum OpenGL
    Réponses: 5
    Dernier message: 14/12/2006, 17h08
  3. [MySQL] Récupérer résultat requête tableau
    Par Invité dans le forum JDBC
    Réponses: 2
    Dernier message: 03/05/2006, 08h22
  4. [VBA-E] Récupérer résultat d'une requête
    Par ragnarök dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 05/04/2006, 16h21
  5. Réponses: 5
    Dernier message: 30/06/2005, 10h28

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