w3schools una trabajar termine que promises promesas platzi funcion esperar encadenamiento con anidadas javascript promise filereader synchronous

una - promises javascript w3schools



Promesas de Javascript con FileReader() (3)

Tengo el siguiente código HTML:

<input type=''file'' multiple>

Y aquí está mi código JS:

var inputFiles = document.getElementsByTagName("input")[0]; inputFiles.onchange = function(){ var fr = new FileReader(); for(var i = 0; i < inputFiles.files.length; i++){ fr.onload = function(){ console.log(i) // Prints "0, 3, 2, 1" in case of 4 chosen files } } fr.readAsDataURL(inputFiles.files[i]); }

Entonces mi pregunta es, ¿cómo puedo hacer que este ciclo sea sincrónico? Eso es primero esperar a que el archivo termine de cargarse y luego avanzar al siguiente archivo. Alguien me dijo que usara JS Promises . Pero no puedo hacer que funcione. Esto es lo que estoy intentando:

var inputFiles = document.getElementsByTagName("input")[0]; inputFiles.onchange = function(){ for(var i = 0; i < inputFiles.files.length; i++){ var fr = new FileReader(); var test = new Promise(function(resolve, reject){ console.log(i) // Prints 0, 1, 2, 3 just as expected resolve(fr.readAsDataURL(inputFiles.files[i])); }); test.then(function(){ fr.onload = function(){ console.log(i); // Prints only 3 } }); }; }

Gracias por adelantado...


La naturaleza de FileReader es que no puede hacer que su operación sea sincrónica.

Sospecho que realmente no necesita o desea que sea sincrónico, solo que desea obtener las URL resultantes correctamente. Si es así, no creo que las promesas realmente ayuden. En su lugar, solo haga un seguimiento de cuántas operaciones pendientes tiene para que sepa cuándo ha terminado:

var inputFiles = document.getElementsByTagName("input")[0]; inputFiles.onchange = function(){ var data = []; // The results var pending = 0; // How many outstanding operations we have // Schedule reading all the files (this finishes before the first onload // callback is allowed to be executed) Array.prototype.forEach.call(inputFiles.files, function(file, index) { // Read this file, remember it in `data` using the same index // as the file entry var fr = new FileReader(); fr.onload = function() { data[index] = fr.result; --pending; if (pending == 0) { // All requests are complete, you''re done } } fr.readAsDataURL(file); ++pending; }); }

O si por algún motivo desea leer los archivos secuencialmente (pero aún de forma asíncrona), puede hacerlo programando la próxima llamada solo cuando la anterior esté completa:

// Note: This assumes there is at least one file, if that // assumption isn''t valid, you''ll need to add an up-front check var inputFiles = document.getElementsByTagName("input")[0]; inputFiles.onchange = function(){ var index = 0; readNext(); function readNext() { var file = inputFiles.files[index++]; var fr = new FileReader(); fr.onload = function() { // use fr.result here if (index < inputFiles.files.length) { // More to do, start loading the next one readNext(); } } fr.readAsDataURL(file); } }


Si quieres hacerlo de forma secuencial (no sincronizada) con Promises, podrías hacer algo como:

var inputFiles = document.getElementsByTagName("input")[0]; inputFiles.onchange = function(){ var promise = Promise.resolve(); inputFiles.files.map( file => promise.then(()=> pFileReader(file))); promise.then(() => console.log(''all done...'')); } function pFileReader(file){ return new Promise((resolve, reject) => { var fr = new FileReader(); fr.onload = resolve; // CHANGE to whatever function you want which would eventually call resolve fr.readAsDataURL(file); }); }


Modificamos la respuesta de midos para que funcione:

function readFile(file){ return new Promise((resolve, reject) => { var fr = new FileReader(); fr.onload = () => { resolve(fr.result ) }; fr.readAsText(file.blob); }); }