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 :

Compréhension du mécanisme FileReader


Sujet :

JavaScript

  1. #1
    Membre très actif
    Inscrit en
    Juin 2007
    Messages
    259
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 259
    Par défaut Compréhension du mécanisme FileReader
    Bonjour,

    Je ne comprends pas bien comment fonctionne FileReader.
    J'ai lu plusieurs doc et tutos, vu des exemples descriptifs mais pas explicatifs !
    Cela se borne à dire de "faire comme ça" et c'est tout, sans aller dans l'explication du mécanisme. Bon, je me doute que c'est de ma faute, mais je ne sais pas ou chercher !!!
    Voici un exemple de mon code pour lire un fichier en local :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    function verif_file() {
            var fileInput = document.querySelector('#fichier');
            var reader = new FileReader();
            reader.onload = function() { alert(reader.result) ; ret=reader.result}
            reader.readAsText(fileInput.files[0]);
            alert(ret) ;
            return false ;
    }
    Lorsque je choisis un fichier et que se lance la fonction verif_file(), le premier "alert()" dans le reader.onload me donne ce que je veut mais l'affectation à ret ne fonctionne pas car le alert(ret) me rend ensuite une chaine vide !
    Je me dis que l'objet ret n'est pas connu dans la fonction donc je fais un var ret = "" avant d'appeler reader.onload() mais même résultat. J'ai essayé de déclarer le ret en global en dehors de toute fonction mais pareil !
    Je ne comprend pas comment récupérer ret en dehors du reader.onload() !
    Je pense qu'il s'agit d'une closure on un truc comme ça mais je n'arrive pas à voir comment cela fonctionne.
    Merci !

  2. #2
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    1 132
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 132
    Par défaut
    Bonjour,

    As-tu essayé d'inverser ta séquence en affectant d'abord ret ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ret=reader.result; alert(res);
    Sinon, es-tu certain que reader.readAsText() a un fonctionnement synchrone et donc que reader.onload() est bien exécuté avant ton alert(ret) de la ligne 6 ?

    devyan

  3. #3
    Membre très actif
    Inscrit en
    Juin 2007
    Messages
    259
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 259
    Par défaut
    oui, j'ai interverti en affectant d'abord la variable puis en faisant un alert sur la variable dans la fonction onload() et j'ai le bon comportement.
    Pour la méthode onload() sur un obje de type FileReader il est dit :

    onload
    Called when the read operation is successfully completed.
    Donc cette fonction est appelée une fois que le reader.readAsText() a été fait avec succès.

  4. #4
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    1 132
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 132
    Par défaut
    Oui elle est exécutée une fois le fichier lu mais la question était de savoir si pendant la lecture du fichier l'exécution du code s'arrête ou si tu risque de demander d'afficher "ret" alors qu'elle n'a pas encore été initialisée par [codeinline]reader.onload()[codeinline].

    devyan.

  5. #5
    Membre très actif
    Inscrit en
    Juin 2007
    Messages
    259
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 259
    Par défaut
    Hmmmm, je vois, je ne sais pas...
    En fait j'essaye de reproduire un peu ceci (exemple pour afficher des miniatures)
    Bon, en fait je ne veux pas afficher de miniatures mais à la place je veux tout de même modifier le DOM. Je récupère la valeur d'un champ input avec un getElementById, je modifie ensuite cette valeur dans le onload() mais en sortant, l'élément n'a pas été modifié ! il garde son ancienne valeur...
    J'ai recopié le code comme l'exemple ci dessus en modifiant ma fonction mais lorsque j'envoie mon formulaire, l'input n'a pas été changé...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function verif_file() {
        var fileInput = document.querySelector('#fichier');
            var reader = new FileReader();
            reader.onload = (function() {
                return function(e) {
                    document.getElementById('input1').value = e.target.result ;
                };
            })(f);
            var f=fileInput.files[0] ;
            reader.readAsText(f);
            return true ;
    }
    Mon element input1 a comme valeur "toto" au départ dans mon DOM au chargement de la page.
    Lors du clic sur le bouton de soumission lors du choix du fichier, la fonction onload() devrait le modifier pour lui faire prendre la valeur contenue dans le fichier ("titi") : mais une fois mon formulaire soumis et que je récupère mes paramètres, j'ai toujours "toto" comme valeur et pas "titi" !
    Alors que si je vais un alert(e.target.result) dans mon onload(), je vois effectivement "titi" : j'en conclus que tout se passe correctement dans la fonction mais en sortant de la fonction, c'est comme si rien ne s'était passé.
    Là, j'ai pourtant repris l'exemple tel quel en l'adaptant à mes besoins...

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Ça s'appelle de la programmation asynchrone.

    En résumé, cette fonction onload n'est pas là pour faire joli.
    Elle est appelée quand le fichier a été correctement chargé.

    Ce qui signifie, évidemment, que tout le reste se fait à un autre moment que quand le fichier a été chargé.
    readAsText() lance la lecture du fichier, mais il n'attend pas que ce soit fini. Ce n'est pas son problème. L'exécution continue, et à ce moment-là la lecture du fichier a tout juste commencé depuis quelques nanosecondes. onload n'a donc pas été appelé et tout ce qui va être fait par onload n'est pas encore fait.

    La raison en est simple : supposons que le fichier soit sur un réseau ou fasse plusieurs mégas. Le lire prend alors plusieurs secondes. Le JavaScript ne peut pas se permettre de durer plusieurs secondes d'exécution, cela bloquerait complètement la page.
    Alors à la place, le travail se fait en arrière-plan, et une fonction JavaScript est appelée quand il est fini.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre très actif
    Inscrit en
    Juin 2007
    Messages
    259
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 259
    Par défaut
    Merci de ta réponse.
    En mettant en route firebug pendant l'exécution et en ouvrant la fenetre de debug sur la ligne qui contient mon input avec la value toto d'origine, je vois bien en direct que le DOM est modifié ! le value='toto' deviens bien value='titi' !
    Je ne comprends alors pas pourquoi le formulaire envoie toto et pas titi...

  8. #8
    Membre très actif
    Inscrit en
    Juin 2007
    Messages
    259
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 259
    Par défaut
    Bon alors en fait j'ai ajouté une boucle dans la fonction principale, avant mon return, qui teste la valeur de reader.readyState et qui ne rend pas la main tant qu'elle n'est pas à 2, indiquant que la lecture est complète.
    Et là, mon formulaire envoie bien la bonne valeur !
    Je vais ajouter quelques controles pour rendre la main au bout d'un certain temps si rien ne se passe !
    Comme c'est pour une appli en réseau local, cela va assez vite. Mais s'il y a d'autres solutions, je suis preneur.
    Merci.

  9. #9
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    1 132
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 132
    Par défaut
    Re-bonjour,

    C'est parce que lorsque tu utilises le mode débug tu laisses le temps au chargement du fichier de se faire.

    Comme ton événement onload() est déclenché en parallèle (en asynchrone) il peut continuer à se faire alors que tu as un point d'arret sur le processus principal.

  10. #10
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Citation Envoyé par fabrice91 Voir le message
    Mais s'il y a d'autres solutions, je suis preneur.
    Une autre solution, ça je ne sais pas. Question difficile. Humm, par exemple, faire faire le travail par la fonction onload ? Celle qui existe précisément pour ça ?
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  11. #11
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    696
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Décembre 2007
    Messages : 696
    Par défaut
    bonjour. pourrais-tu afficher ton code stp ? cette discussion m'intéresse beaucoup !

    merci

  12. #12
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    1 132
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 132
    Par défaut
    Bonjour,

    Concrètement tu ne peux pas utiliser "verif_file()" comme une focntion qu retourne true|false pour poursuivre ton traitement.

    il faut l'utiliser pour exécuter ton code dans une "callback" qui sera comme l'indique thelvin appelée dans reader.onload().

    AU lieu de quelque chose comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    function verif_file() {
    	...
    	return reader.result;
    }
     
    ...
     
    if (verif_file == ???) {
    	// cas fichier OK
    } else {
    	// cas fichier KO
    }
    tu aurais :
    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
     
    function verif_file(callbackFunc) {
    	var fileInput = document.querySelector('#fichier');
    	var reader = new FileReader();
    	reader.onload = function() { 
    			if (typeof callbackFunc == "fucntion") {
    				callbackFunc(reader.result); 
    			}
    		};
    	reader.readAsText(fileInput.files[0]);
     
    }
     
    ...
     
    verif_file(function (resultat) {
    	if (resuiltat == ???) {
    		// cas fichier OK
    	} else {
    		// cas fichier KO
    	}
    });
    Il faut bien comprendre que le chargement du fichier se fait (comme l'a déjà expliqué thelvin) en parallèle du code de "démarrage" de l'action.

    devyan.

  13. #13
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    696
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Décembre 2007
    Messages : 696
    Par défaut
    si je puis me permettre, j'ai utilisé ta méthode comme tu peux le voir. cependant, ma collection d'objet "fileCollection" est désespérément vide :/.
    que puis-je faire ?

    Merci

    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
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    var fileCollection = [];
     
                   /* 
    		* Public
    		* Get file information from the input field
    		*/
    		this.GetFileFromInput = function() {
    			console.log('public method UploadData:GetFileFromInput() called!');
     
    			var files = elem[0].files,
    				Id = undefined;
     
    			$.each(files, function(index, file) {
    				var ifFileExists = FileExists(file);
    				var isSizeOk = ((settings.fileSizeLimit === undefined) || (file.size <= (settings.fileSizeLimit * 1000)));
    				var isFileLimitOk = ((settings.fileLimit === undefined) || (fileCollection.length < settings.fileLimit));
    				if(!ifFileExists && isSizeOk && isFileLimitOk)
    				{
    					obj.FileReader(file, function(datafile) {
    						RecordFileData(file, datafile);
    					});
    				}
    			});
     
    			alert(JSON.stringify(fileCollection));
    		};
     
    		/* 
    		* Public
    		* Get file data
    		*/
    		this.FileReader = function(file, callbackFunc) {
    			console.log('private method UploadData:FileReader() called!');
     
    			var fileReader = new FileReader();
     
    			fileReader.onload = function() {
    				if (typeof callbackFunc == "function") {
    					callbackFunc(fileReader.result); 
    				}
    			};
     
    			fileReader.readAsDataURL(file);
    		};
     
    		/* 
    		* Private
    		* Record many information about file (Id, rate, value, isInQueue)
    		*/
    		var RecordFileData = function(file, datafile) {
    			console.log('private method UploadData:RecordFileData() called!');
     
    			file.Id = CreateGuid();
    			file.rate = 0;
    			file.value = datafile;
    			fileCollection.push(file);
    			obj.SetIsInQueue(file, false);
    		};

  14. #14
    Membre éclairé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    696
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Décembre 2007
    Messages : 696
    Par défaut
    Ah mais lol, l'astuce bidon que je viens de trouver !!!

    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
    this.GetFileFromInput = function() {
    			console.log('public method UploadData:GetFileFromInput() called!');
     
    			var files = elem[0].files,
    				Id = undefined;
     
    			$.each(files, function(index, file) {
    				var ifFileExists = FileExists(file);
    				var isSizeOk = ((settings.fileSizeLimit === undefined) || (file.size <= (settings.fileSizeLimit * 1000)));
    				var isFileLimitOk = ((settings.fileLimit === undefined) || (fileCollection.length < settings.fileLimit));
    				if(!ifFileExists && isSizeOk && isFileLimitOk)
    				{
    					obj.FileReader(file, function(datafile) {
    						RecordFileData(file, datafile);
    					});
    				}
    			});
     
    			setTimeout(function(){
    				alert(JSON.stringify(fileCollection));
    			}, 0);
    		};
    un settimeout de .... 0 seconde !!

    EDIT :

    J'ai rien dis, le problème est le même pour le retour du settimeout :/

  15. #15
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    En quelle langue faut-il vous dire à tous les deux que les résultats ne seront visibles que quand le callback sera terminé ?

    "Ben, du coup, comment est-ce qu'on attend la fin du callback ?"
    => J'en sais rien, on programme ce qu'on veut faire à la fin du callback, par exemple ? C'est-à-dire, de l'autre côté du callback que le début du callback ?
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 14/09/2009, 13h50
  2. compréhension du profil d'une fonction
    Par lor dans le forum MFC
    Réponses: 7
    Dernier message: 08/01/2004, 12h59
  3. [FLASH MX] Prob de compréhension des bouttons
    Par WriteLN dans le forum Flash
    Réponses: 13
    Dernier message: 16/10/2003, 17h01
  4. onclipevent (problème de compréhension)
    Par stephane eyskens dans le forum Flash
    Réponses: 8
    Dernier message: 24/09/2003, 15h09
  5. Problème de compréhension des ensembles
    Par Cornell dans le forum Langage
    Réponses: 6
    Dernier message: 07/02/2003, 22h07

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