web-dev-qa-db-fra.com

Lire un fichier de manière synchrone en Javascript

Je voudrais lire un fichier et le convertir en une chaîne encodée en base64 en utilisant l'objet FileReader. Voici le code que j'utilise:

 
 var reader = new FileReader (); 
 reader.onloadend = function (evt) {
 // le fichier est chargé 
 result_base64 = evt .target.result; 
}; 
 reader.readAsDataURL (fichier); 
 
 

Mais dans ce cas, j'obtiens le résultat de la conversion dans le gestionnaire d'événements (événement onLoadEnd). Je voudrais une méthode synchrone. Existe-t-il un moyen pour la méthode "readAsDataURL" de renvoyer directement la valeur de la variable 'result_base64'?

Merci

33
Laila

Les tâches synchrones (blocage) sont généralement mauvaises. S'il n'y a aucune raison réelle de le faire de manière asynchrone, je vous recommande fortement d'utiliser le rappel d'événement.

Imaginez que votre fichier soit cassé et que l'api HTML5 ne puisse pas être lu, il ne vous donnera pas le résultat. Cela casserait votre code et bloquerait le site. Ou, quelqu'un pourrait sélectionner un fichier de 10 Go, ce qui gèlerait votre page HTML jusqu'à ce que le fichier soit complètement chargé. Avec ce gestionnaire d'événements asynchrone, vous pouvez détecter les erreurs possibles.

Pour contourner les limitations avec les rappels, j'utilise une astuce simple:

var ready = false;
var result = '';

var check = function() {
    if (ready === true) {
         // do what you want with the result variable
         return;
    }
    setTimeout(check, 1000);
}

check();

var reader = new FileReader();
reader.onloadend = function(evt) {
    // file is loaded
    result = evt.target.result;

    ready = true;
};
reader.readAsDataURL(file);

la fonction de vérification, vérifie toutes les secondes si la variable de drapeau prêt est définie sur true. Si c'est le cas, vous pouvez être sûr que le résultat est disponible.

Ce n'est peut-être pas la meilleure pratique de le faire, mais j'ai fait une application Web en utilisant cette technique environ 30 fois avec plus de 10 setTimeouts en même temps, et je n'ai rencontré aucun problème jusqu'à présent.

17
David Fariña

Vous pouvez utiliser la norme FileReaderSync , qui est une version plus simple, synchrone et bloquante de l'API FileReader, similaire à ce que vous utilisez déjà:

let reader = new FileReaderSync();
let result_base64 = reader.readAsDataURL(file); 

console.log(result_base64); // aGV5IHRoZXJl...

Gardez à l'esprit que cela n'est disponible que dans les threads de travail, pour des raisons évidentes.


Si vous avez besoin d'une solution pour le thread principal qui "se lit comme" une API synchrone, vous pouvez encapsuler le FileReader async dans une promesse et utiliser des fonctions async (vous devrez peut-être transpiler):

async function readFileAsDataURL(file) {
    let result_base64 = await new Promise((resolve) => {
        let fileReader = new FileReader();
        fileReader.onload = (e) => resolve(fileReader.result);
        fileReader.readAsDataURL(file);
    });

    console.log(result_base64); // aGV5IHRoZXJl...

    return result_base64;
}
2
John Weisz

Pour lire le contenu d'un fichier de manière synchrone, utilisez fs.readFileSync

var fs = require('fs');
var content = fs.readFileSync('myfilename');
console.log(content);

fs.createReadStream crée un ReadStream .

0
Jonathan Thurft