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

jQuery Discussion :

jquery.deferred, fancytree, et IIFE


Sujet :

jQuery

  1. #1
    Membre Expert
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    1 616
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 616
    Par défaut jquery.deferred, fancytree, et IIFE
    Bonjour

    Une question sur un phénomène qui m'échappe un peu, que je présume lié à l'asynchronisme mais sans vraiment arriver à me l'expliquer.
    Enfin en tout cas je cherche un éclairage.

    Donc voici mon bout de 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
    20
    21
    22
    23
    24
    25
    26
    27
     
    function expandResultNodes(responseText)  { 
        var result_keys=[];
        $.each(responseText, function( index, keypath) {
            result_keys.push(keypath.split("/").pop());
        });
        var FTPtree = $("#Tree_sasFTP").fancytree("getTree") ;
     
        // Use deferred promise:
     
        FTPtree.loadKeyPath(responseText).done(function(){
            defferedFilterNodes(FTPtree);
        });
        // FTPtree.loadKeyPath(responseText).done(
            // defferedFilterNodes(FTPtree)
        // );
     
        function defferedFilterNodes (tree){
            tree.filterNodes(function(node) {
                console.log("filtering " + node.key);
                return result_keys.some(function(element) {
                    // checks whether a result_keys element equals node key
                    return element == node.key;
                });
            });
        }       
    }
    j'envoie en AJAX une requête de recherche de mots-clés sur mon serveur, la recherche s'effectue sur le serveur sur une partie du file system qui correspond à une zone de dépose FTP, le serveur renvoie une réponse en JSON qui est constituée d'un tableau de chemins de clefs. Exemple de réponse mis en forme par firefox :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
    0	"/_f83b45b7c4d40be3b25b7abfcb7226c4/_eb8cf44ea2366ae3cf1af572d5a818e0/_393d735d160b9d21ddde00b739991e59"
    1	"/_f83b45b7c4d40be3b25b7abfcb7226c4/_eb8cf44ea2366ae3cf1af572d5a818e0/_32a9a6fc7652124f1882f52e2316ee0e"
    2	"/_f83b45b7c4d40be3b25b7abfcb7226c4/_eb8cf44ea2366ae3cf1af572d5a818e0/_32a9a6fc7652124f1882f52e2316ee0e/_19a2fd29b73244e41f9eaa4ec6dc5e79/_fb58a0b2d0e222117b83e361be8643e4"
    3	"/_f83b45b7c4d40be3b25b7abfcb7226c4/_eb8cf44ea2366ae3cf1af572d5a818e0/_32a9a6fc7652124f1882f52e2316ee0e/_19a2fd29b73244e41f9eaa4ec6dc5e79/_32a1178799b476d197251c2d1e617903"
    [...]
    24	"/_f83b45b7c4d40be3b25b7abfcb7226c4/_eb8cf44ea2366ae3cf1af572d5a818e0/_f45e1e6c72e2e8a80889794671538c6e/_11fe4e4e36adeacf04d8efbffcf4259a/_16b6520368113327455a2574562a902f"
    25	"/_f83b45b7c4d40be3b25b7abfcb7226c4/_eb8cf44ea2366ae3cf1af572d5a818e0/_123fcfdc7ff35b145093d9ff49ada47b"
    Ces clefs sont des éléments identifiants pour les nœuds d'une arborescence représentée par Fancytree : https://github.com/mar10/fancytree

    A la base, avant de recevoir cette réponse Fancytree ne représente que le premier niveau de répertoires, donc la racine et 8 répertoires sous-jacents.

    le code une fois la réponse JSON reçue, charge de manière "lazy" (lazy loading==requêtes AJAX pour chaque nouveau noeud ou branches à visualiser qui n'est pas déjà présent)
    C'est ce que fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FTPtree.loadKeyPath(responseText)
    la doc de cette fonction loadKeyPath ici : http://wwwendt.de/tech/fancytree/doc...ml#loadKeyPath

    puis une fois les branches adéquates chargées, je vais mettre en évidence les résultats de la requête. En fait ces résultats sont les clefs terminales de chaque ligne du tableau des chemins.
    d'où le
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    var result_keys=[];
        $.each(responseText, function( index, keypath) {
            result_keys.push(keypath.split("/").pop());
        });
    qui ne garde que le dernier élément de chaque ligne pour en constituer un nouveau tableau correspondant aux résultats effectifs de la requête.

    et donc à la fin de loadKeyPath, je filtre les résultats avec cette fonctionnalité, extension de fancytree :
    https://github.com/mar10/fancytree/wiki/ExtFilter
    en comparant les éléments du tableau des résultats avec les clefs précédemment chargées, ce que fait la fonction defferedFilterNodes

    le truc c'est que si j'appelle cette fonction directement dans le .done(), seuls les éléments affichés avant l'exécution de loadKeyPath sont filtrés, donc le premier niveau d'arborescence, alors que tous les éléments sont bien chargés
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        FTPtree.loadKeyPath(responseText).done(
            defferedFilterNodes(FTPtree)
        );
    Si j'appelle cette fonction dans le cadre d'une IIFE, ça marche nickel et tous les résultats, toutes les branches == tous les éléments transmis sont bien filtrés et mis en évidence
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        FTPtree.loadKeyPath(responseText).done(function(){
            defferedFilterNodes(FTPtree);
        });
    J'ai bien l'intuition de ce qui se passe, mais je ne sais pas me l'expliquer avec des notions réellement formelles liées à Javascript.

    Quelqu'un saurait il m'expliquer ce phénomène ? aussi bête soit-il ou non ?

  2. #2
    Membre extrêmement actif Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 532
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 532
    Par défaut
    Oui, c'est bien une gestion Asynchrone, et il y a donc une gestion de promesses, ici codées au travers des méthodes done ou "IIFE" qui doit se trouver quelque part dans leur doc..

  3. #3
    Membre Expert
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    1 616
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 616
    Par défaut
    En fait ce que je voulais dire, c'est pourquoi dans un cas, sans l'IIFE, le programme semble voir le DOM avant qu'il n'ai été mis à jour par l'appel à loadKeyPath, et pourquoi si cette même fonction est appelée dans le cadre de l'IIFE, elle voit le DOM tel qu'il a été mis à jour ?

    Je vais poser cette même question sur le forum Fancytree, mais si c'est un mécanisme qui n'est pas lié spécifiquement à Fancytree mais à la gestion des promises et plus généralement au JavaScript, je veux bien que quelqu'un éclaire ma lanterne.

  4. #4
    Membre extrêmement actif Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 532
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 532
    Par défaut
    Quand l'interpréteur JS se retrouve à traiter une fonction asynchrone, il lance un process en parallèle pour s'en occuper, et il continue avec les instruction suivantes, sans ce soucier du résultat ni des changements sur les variables.

    grosso modo
    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    var XYZ = 5;
    fonctionAsync_raz_XYZ();
    console.log(XYZ);  // renvoie 12, XYZ reste inchangée
    // ....
     
    // 10 minutes plus tard quand la fonctionAsync_raz_XYZ() est achevée : 
    console.log(XYZ);  // renvoie 0, XYZ à été remis à zéro par la fonctionAsync_raz_XYZ

    en javascript on parle de fonction asynchrones,
    et jQuery part de l'idée que ce sont des fonctions qui finiront par s'exécuter de maniéré différées, d’où leur nom : defered

  5. #5
    Membre Expert
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    1 616
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 616
    Par défaut
    oui ça pas de souci

    sauf que là tu m’expliques l'asynchronisme, pas ce que je cherche à comprendre. Ni pourquoi l'IIFE casse (ou résoud) ce mécanisme décrit plus haut.

    En gros avec les outils de dev et la console javascript, je vois bien que defferedFilterNodes est appelé à la fin de loadKeyPath, après son exécution complète, et non pas de manière asynchrone, parallèle mais bien comme un callback

    Dans un cas defferedFilterNodes voit le Tree et donc le DOM comme il est avant l'exécution de loadKeyPath, et avec l'IIFE comme il est après. Dans les 2 cas, les fonctions sotn appelées en callback du .done de loadKeyPath

    C'est ça que je ne comprends pas, et c'est plutôt à l'opposé de ce que tu me décris.

    M'enfin je ne comprends pas alors peut-être pas plus ton explication, sauf que je ne vois pas comment tu l'appliques à ce cas concret.

  6. #6
    Membre extrêmement actif Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 532
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 532
    Par défaut
    Si tu dois exploiter le résultat d’une fonction asynchrone, il faut utiliser un mécanisme qui attende la fin de l’exécution de cette fonction async.

    En Javascript ce mécanisme fonctionne en 2 parties*:
    premier partie sur la fonction asynchrone elle même pour qu’elle puisse en voyer un signal comme quoi elle s’est bien terminée terminée ou non, et dans ce cas l’interpréteur active un abandon*;

    en js çà s*‘écrit ; function MuFctAsync() { return new Promise(function(resolve, reject){ … })*; }


    la deuxieme partie c’est la fonction qui appelle la fonction async et qui se charge de traiter la suite et en fonction de statut de retour de cette fct async.

    Comme en JS on est dans un langage objet, il peut y avoir une douzaine de mêmes fonctions Async en même temps et et convient de bien lier ensemble les fonctions qui doivent encadrer les process asynchrone et les fonctions asynchrones elles mêmes.

    Si tu faits les trucs dans le désordre, en liant des parties qui ne se correspondent pas ça ne pourra jamais marcher.

  7. #7
    Membre Expert
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    1 616
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 616
    Par défaut
    Salut
    Petit retour sur le sujet, car même si ça intéresse peu de monde, l'explication n'est pas dans ce que tu décris psychadelic.

    Aucune prétention là-dessus, rien d'offensant pour toi psychadelic , mais ça m'a amené à revisiter plein de concepts du JavaScript pour bien comprendre ce que je faisais.

    donc tout d'abord ce n'est pas une IIFE que d'écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    .done(
            function(){
            defferedFilterNodes(FTPtree);
        });
    pour l'argument de la fonction .done()
    C'est la déclaration d'une fonction anonyme qui elle-même fait appel à defferedFilterNodes avec l'argument que je souhaite lui passer.

    une IIFE en javascript s'écrit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    (function(){
        // code 
        // ...
    })(args);
    Si j'ai bien compris la 1ère paire de parenthèses transforme son contenu en expression, ici la déclaration de fonction anonyme, la dernière paire provoque son exécution immédiate en passant les arguments contenus entre ces dernières parenthèses à l'expression contenue dans la première paire.

    Je me sers de cette forme pour créer un objet qui sert de namespace pour contenir certaines méthodes. C'est à la base du pattern de module.
    Bref...

    en écrivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    FTPtree.loadKeyPath(responseText).done(
            defferedFilterNodes(FTPtree)
        );
    Je passe le résultat de l'appel de la fonction defferedFilterNodes avec l'argument FTPtree à la méthode .done(), quel que soit le résultat de cet appel. Ca ne peut pas marcher. Ca peut peut-être marcher au cas par cas, c'est de toute façon une mauvaise façon de faire.

    la méthode .done(callback) attend de recevoir une fonction comme argument, un callback. Avec une déclaration de fonction anonyme je lui passe effectivement une fonction, dans le second cas je lui passe un résultat à la place d'une fonction, et la fonction a effectivement déjà été exécutée.

    Je voulais pouvoir passer le callback avec un argument explicite non-présent dans ce avec quoi est appelé le callback.
    Je peux gérer cette valeur autrement dans mon code et écrire simplement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FTPtree.loadKeyPath(responseText).done(defferedFilterNodes);
    Ca marche très bien, je passe ici comme callback la référence à une fonction, et non le résultat d'une fonction.

    Ca peut paraitre évident pour beaucoup, cependant je n'avais pas de réponse, en tout cas pas ici, ni de compréhension de ce que observais.

    Cette question m'a amené à revisiter et à travailler en profondeur les concepts basiques du JavaScript, à vraiment remettre en question ma compréhension du langage... Donc tant mieux, je me sens beaucoup plus à l'aise... Mais le chemin est encore long

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 14/01/2005, 10h36
  2. documentation sur deferable
    Par champion dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 13/09/2004, 22h18
  3. [SQL] INITIALLY DEFERRED DEFERRABLE
    Par Boosters dans le forum Administration
    Réponses: 8
    Dernier message: 05/03/2004, 19h05
  4. Fonction IIF
    Par ParisMath dans le forum SQL
    Réponses: 2
    Dernier message: 16/01/2004, 22h18

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