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, await/async ou callback


Sujet :

JavaScript

  1. #1
    Futur Membre du Club
    Inscrit en
    Mai 2004
    Messages
    7
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 7
    Points : 9
    Points
    9
    Par défaut Promise, await/async ou callback
    Bonjour à tous,

    Depuis quelques années, je n'ai pas développé en JS et j'ai besoin de reprendre un script tout simple mais il ne exécute pas dans l'ordre.

    Le voici :
    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
     
    getNotificationSounds2(serialOrName, idSound, callback) 
        {
        console.log("1");
            let result="";        
            this.getNotificationSounds(serialOrName, (err, res) => 
            {
                console.log("2");
                res.notificationSounds.forEach(function(item, index) {
                    if (item['id'] == idSound) {
                    result=item;            
                    console.log("3");
                    }
                });
            });
        console.log("4");
        return result;
        }
    Je me retrouve avec 1 puis 4 puis 2 puis 3

    Je sais c'est l'erreur classique de JS en synchrone / asynchrone et j'imagine que c'est tout simple à changer mais j'ai passé l'après midi a essayer de retrouver comment faire.

    Une bonne âme pourrait m'aider ?

    Merci

  2. #2
    Invité
    Invité(e)
    Dernière modification par Invité ; 04/11/2019 à 16h30.

  3. #3
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 890
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 890
    Points : 3 729
    Points
    3 729
    Par défaut
    Salut,

    Citation Envoyé par lionelll Voir le message
    Je me retrouve avec 1 puis 4 puis 2 puis 3
    Oui c'est normal...

    Et effectivement je pense que c'est un problème lié à l’asynchrone, regarde ce cas similaire #2* pour une explication...

    * Dans le message il y a un autre lien...


    Citation Envoyé par lionelll Voir le message
    ... et j'imagine que c'est tout simple à changer mais j'ai passé l'après midi a essayer de retrouver comment faire.
    Ben je ne sais si c'est simple à changer, il faudrait qu'on sache ce que tu veux faire exactement...

    Je ne sais pas si il y a moyen de faire en sorte que ton item soit retourné par la fonction getNotificationSounds2 mais à priori ne devrais-tu pas plutôt utiliser la fonction callback passée en troisième paramètre de la fonction getNotificationSounds2 (serialOrName, idSound, callback) pour effectuer le traitement voulue ?

    D'ailleurs si tu ne l'utilises pas pour cela alors pourquoi la passer en paramètre ?

    Citation Envoyé par jreaux62 Voir le message

    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
    getNotificationSounds2(serialOrName, idSound, callback) 
        {
        console.log("1");
            let result="";        
            this.getNotificationSounds(serialOrName, (err, res) => 
            {
                console.log("2");
                res.notificationSounds.forEach(function(item, index) {
                    if (item['id'] == idSound) {
                    result=item;            
                    console.log("3");
                    return result;
                    }
                });
            });
        }
    Je ne suis pas sûr que cela va marcher*, il faudrait qu'on sache ce qui est voulu exactement...

    * Je dis ça pour deux raisons :

    1- Le return result; est à l'intérieur de la fonction du forEach or on ne récupère pas ce qui est retourné par cette fonction...

    2- Comme expliqué ici : "Il n'existe aucun moyen d'arrêter une boucle forEach en dehors de lever une exception..."

    Et apparemment ça vaut aussi pour un return (la boucle continue même après un return), exemple :

    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    var array1 = ['a', 'b', 'c'];
     
    array1.forEach(function (element) {
        console.log(element);
     
        if (element == 'b') {
            console.log("element est égal à 'b'");
            return element
        }
     
    });

    Cela affiche ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    a
    b
    element est égal à 'b'
    c
    On voit que la lettre 'c' est affichée malgré l’exécution de return element...

    Problème pas évident mine de rien...

  4. #4
    Invité
    Invité(e)
    Par défaut
    @Beginner.

    Alors, là, j'en apprends une bien bonne !
    JS ne se comporte pas comme PHP...

    En PHP :
    Code php : 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
    <?php
    function afficher()
    {
    	$array1 = ['a', 'b', 'c'];
    	$result = '';
    	foreach($array1 as $element) {
    		echo $element.'<br/>';
    		if ($element == 'b') {
    			$result = "element est égal à 'b'".'<br/>';
    			echo $result;
    			return $result; // en PHP : arrête la boucle et sort de la fonction...
    		}
    	}
    }
    $affichage = afficher();
    echo 'affichage : '.$affichage; 
    ?>
    On obtient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    a
    b
    element est égal à 'b'
    affichage : element est égal à 'b'
    Alors qu'en JS :
    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
    function afficher()
    {
    	var array1 = ['a', 'b', 'c'];
    	var result = '';
    	array1.forEach(function (element) {
    		console.log(element);
    		if (element == 'b') {
    			result = "element est égal à 'b'";
    			console.log( result );
    			return result;
    		}
    	});
    }
    var affichage = afficher();
    console.log('affichage : ' + affichage);
    On obtient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    a
    b
    element est égal à 'b'
    c
    affichage : undefined
    Dernière modification par Invité ; 04/11/2019 à 16h48.

  5. #5
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 890
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 890
    Points : 3 729
    Points
    3 729
    Par défaut
    Et oui il y a de quoi pleurer lol...

    Pas trop quand même...

  6. #6
    Invité
    Invité(e)
    Par défaut
    Bonsoir,

    @jreaux62 : Encore faudrait-il comparer des éléments comparables .

    L'appel JS de Array.forEach() équivaut à utiliser array_walk() du PHP, les deux utilisant une fonction callback. De ce fait, le return nous fera seulement quitter ce callback et non la boucle sur le tableau. Boucle qui s'effectue un niveau au dessus implicitement par la fonction (ignorant complètement l'éventuelle valeur retournée par le callback), et qui se poursuivra à moins qu'une exception ne soit lancée.

    Comparons donc soit une boucle classique : le return nous fera donc quitter de suite la fonction afficher() (et donc la boucle).
    Code php : 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
    <?php
    function afficher()
    {
    	$array1 = ['a', 'b', 'c'];
    	$result = '';
    	foreach($array1 as $element) {
    		echo $element.'<br/>';
    		if ($element == 'b') {
    			$result = "element est égal à 'b'".'<br/>';
    			echo $result;
    			return $result; // en PHP : arrête la boucle et sort de la fonction...
    		}
    	}
    }
    $affichage = afficher();
    echo 'affichage : '.$affichage; 
    ?>
    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function afficher()
    {
    	let array1 = ['a', 'b', 'c'];
    	let result = '';
    	for (let element of array1) {
    		console.log(element);
    		if (element == 'b') {
    			result = "element est égal à 'b'";
    			console.log( result );
    			return result;
    		}
    	}
    }
    let affichage = afficher();
    console.log('affichage : ' + affichage);
    a
    b
    element est égal à 'b'
    affichage : element est égal à 'b'
    a
    b
    element est égal à 'b'
    affichage : element est égal à 'b'

    Soit l'appel à ces fonctions : le return nous fera juste quitter le callback passé à la fonction forEach()/array_walk(), mais pas la boucle.
    (array_walk() retournant simplement true, et forEach() undefined, inutile de récupérer leur sortie.)
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?php
    function afficher()
    {
    	$array1 = ['a', 'b', 'c'];
    	$result = '';
    	array_walk($array1, function ($element) {
    		echo $element.'<br/>';
    		if ($element == 'b') {
    			$result = "element est égal à 'b'".'<br/>';
    			echo $result;
    		}
    	});
    }
    afficher();
    ?>
    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function afficher()
    {
    	let array1 = ['a', 'b', 'c'];
    	let result = '';
    	array1.forEach(function (element) {
    		console.log(element);
    		if (element == 'b') {
    			result = "element est égal à 'b'";
    			console.log( result );
    		}
    	});
    }
    afficher();
    a
    b
    element est égal à 'b'
    c
    a
    b
    element est égal à 'b'
    c
    Pas si différents au final .

    @lionelll : Pour trouver l'élément d'un tableau qui vérifie un certain critère, Array.find() est plus indiqué :
    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    let item_found = res.notificationSounds.find( item => item['id'] == idSound );
    // = undefined si non trouvé

    Pour ce qui est de gérer un appel asynchrone, comme tu t'en es rendu compte, il faut savoir que l'appel d'une fonction asynchrone n'est pas bloquant. C'est à dire que l'exécution du code ne s'arrête pas au niveau de l'appel pour attendre la fin du traitement, et ne reprendre qu'une fois terminé. Non, l'exécution continue, et le traitement se fait en parallèle.
    Ainsi ton result (pas encore obtenu) est déjà retourné (vide) par la fonction, alors que le traitement n'est pas encore terminé (voire a à peine débuté).

    Pour ce faire il existe deux solutions :

    1) Passer, comme tu sembles le faire, une fonction callback que tu devras appeler lorsque le traitement sera terminé en lui passant l'éventuel résultat (ici l'item correspondant au critère) :
    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    getNotificationSounds2(serialOrName, idSound, callback /* <=== ici */) 
    {
    	this.getNotificationSounds(serialOrName, (err, res) => 
    	{
    		callback( res.notificationSounds.find( item => item['id'] == idSound ) );
    	});
    }
    L'appel de la fonction se fera alors de la manière suivante :
    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    getNotificationSounds2(serialOrName, idSound, item => {
        // utilisation de l'item
    });

    2) Retourner une Promise depuis la fonction : le résultat est alors transmis par l'appel à resolve() (ou si erreur, l'appel à reject()) :

    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    getNotificationSounds2(serialOrName, idSound) 
    {
    	return new Promise( (resolve, reject) => {
    		this.getNotificationSounds(serialOrName, (err, res) => 
    		{
    	            resolve( res.notificationSounds.find( item => item['id'] == idSound ) );
    	        });
            });
    }
    L'appel s'effectuera alors de la manière suivante :
    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    getNotificationSounds2(serialOrName, idSound)
    .then( item => {
        // utilisation de l'item
    })
    .catch( err => {
        // traitement de l'erreur
    });
    Dernière modification par Invité ; 16/02/2020 à 19h42.

  7. #7
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 890
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 890
    Points : 3 729
    Points
    3 729
    Par défaut
    Merci Winjerome pour ces explications supplémentaires, c'est instructif...

  8. #8
    Invité
    Invité(e)
    Par défaut
    @Winjerome

    J'ai comparé .forEach() JS et foreach() PHP, car elles ont le même nom.
    Et bien que les scripts soient très similaires, le comportement du return est différent.

    La comparaison n'a rien de ridicule, puisque je pensais, a tort, que le comportement serait le même.
    D'où mon 1er message, supprimé depuis.


    Sinon, il ne fallait pas l'appeler Array.forEach(), mais Array.arrayWalk() !
    Dernière modification par Invité ; 05/11/2019 à 14h18.

  9. #9
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 749
    Points
    4 749
    Par défaut
    Citation Envoyé par jreaux62 Voir le message
    Sinon, il ne fallait pas l'appeler Array.forEach(), mais Array.Walk() !!
    comprens pas, pour moi la méthode JS forEach() fonctionne bien de manière synchrone ( comme le foreach() du PHP ) le décalage est du au fait qi'il est placé à l'intérieur d'une fonction qui elle est asynchrone ( getNotificationSounds )

  10. #10
    Invité
    Invité(e)
    Par défaut
    @psychadelic
    Il ne s'agissait pas de résoudre la problématique de l'asynchrone (Winjerome y a répondu).
    C'était juste pour illustrer que dans le .forEach JS et le foreach PHP, le return ne se comporte pas de la même façon.

Discussions similaires

  1. NodeJS : Promises & async/await
    Par Firlfire dans le forum NodeJS
    Réponses: 0
    Dernier message: 24/06/2019, 18h01
  2. Await, Async, et Task
    Par lamouche42 dans le forum C#
    Réponses: 0
    Dernier message: 10/05/2019, 00h33
  3. WP 7 et 8 : utiliser les mots clefs await/async et Task<T>
    Par rolandl dans le forum Windows Phone
    Réponses: 2
    Dernier message: 27/03/2013, 09h40
  4. Async et Await sur fonction perso
    Par Squall____ dans le forum VB.NET
    Réponses: 0
    Dernier message: 11/09/2012, 15h03
  5. Async/Await avec Silverlight & WCF
    Par Joffrey Kern dans le forum Silverlight
    Réponses: 5
    Dernier message: 24/05/2012, 09h45

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