estoy usando fileReader para cargar imágenes, cuando las imágenes terminen de cargarse, quiero enviarlas al servidor.
mi problema es que cuando hay más de 1 imagen envía múltiples solicitudes, porque tengo for loop. ¿Cómo puedo hacer que funcione?
for (let file of selectedFiles) { const fileName = file.name; const reader = new FileReader(); reader.readAsArrayBuffer(file); reader.onload = () => { const image = reader.result as any; var base64 = btoa( new Uint8Array(image) .reduce((data, byte) => data + String.fromCharCode(byte), '') ); imageArray.push({ fileName: fileName, content: base64 }); console.log(imageArray); this.service.create(this.finalData).subscribe({ next: data => { console.log(data); this.openSnackBar("Success", 'x'); }, error: error => { console.error('There was an error!', error); } }) } }Si está lidiando con varias cosas asincrónicas a la vez, se ahorrará mucho esfuerzo al usar promesas.
Comience escribiendo una función que tome un archivo y devuelva una promesa que resuelva los datos que desea.
Definiré FileData aquí para dejar claro cómo funcionan las cosas más adelante.
type FileData = { fileName: string; content: string; // base64 encoded }; const getFileData = (file) => { const fileName = file.name; const promise = new Promise( (res, rej) => { const reader = new FileReader(); reader.readAsArrayBuffer(file); reader.onload = () => { const image = reader.result as any; var base64 = btoa( new Uint8Array(image) .reduce((data, byte) => data + String.fromCharCode(byte), '') ); const data: FileData = { fileName: fileName, content: base64 }; res(data) }; }); return promise; };Luego haga su bucle pero use la función para obtener sus datos y reunir los resultados en una matriz.
const promises = []; for (let file of selectedFiles) { promises.push(getFileData(promises)); }; Luego use Promise.all para ejecutar otra función una vez que se resuelvan todas las promesas y tenga los datos.
Promise.all(promises).then((dataArray: FileData[]) => { // Now work with dataArray and upload all the data in the array in one go }); Dicho eso. Buscaría cambiar el servidor para admitir una solicitud estándar con formato MIME de varias partes y luego cargar los datos usando FormData en lugar de convertir todo a base64 yo mismo.
const data = new FormData(document.getElementById('myForm'); const responsePromise = fetch('/url', { method: "POST", body: data });… es mucho menos esfuerzo que el anterior! Y envía todos los mismos datos (solo que en un formato diferente).