Estoy consumiendo una API en la que quiero mostrar los datos generados en mi HTML. Para eso estoy creando los elementos div usando JavaScript. Al mostrar la información lo hace sin problemas, pero cada vez que actualizo la página, los datos los muestra en un orden diferente. Es decir, si tengo 3 divs, el div que estaba primero ahora aparecerá en último lugar y, por lo tanto, el orden cambia cada vez que actualizo la página.
Este es mi código Javascript:
const cargar_noticias_recientes = async () => { const noticias_recientes = document.querySelector('#pnl-body-content-card-reci'); const res = await fetch(`WebService_Default.asmx/cargar_card_noticia_recientes`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '' }); const datos = await res.json(); let nuevos = [...datos.d]; nuevos.map(async nuevo => { const div = document.createElement('div'); const peticion = await fetch(`http://localhost:51482/api/values/${nuevo[3]}`, { method: 'GET' }); const imagen = await peticion.blob(); const url = URL.createObjectURL(imagen); div.innerHTML = ` <div class="body-card body-card-reci ${nuevo[0]}"> <div class="card-title"> <span>Nuevo</span> </div> <div class="img-card"> <div class="img" style="background-image: url(${url});"></div> </div> <div class="content-card"> <p> <i class="fas fa-tags"></i> ${nuevo[1]} </p> </div> </div> ` noticias_recientes.appendChild(div); }); }Su problema está relacionado con el uso de asynchronous.
nuevos.map(async nuevo => { const div = document.createElement('div'); const peticion = await fetch(`http://localhost:51482/api/values/${nuevo[3]}`, { method: 'GET' }); const imagen = await peticion.blob(); const url = URL.createObjectURL(imagen); div.innerHTML = ` <div class="body-card body-card-reci ${nuevo[0]}"> <div class="card-title"> <span>Nuevo</span> </div> <div class="img-card"> <div class="img" style="background-image: url(${url});"></div> </div> <div class="content-card"> <p> <i class="fas fa-tags"></i> ${nuevo[1]} </p> </div> </div> ` noticias_recientes.appendChild(div); });En esta función haces una búsqueda. Esta es una solicitud HTTP que tiene un tiempo de ejecución más o menos aleatorio. La primera búsqueda que termine será el primer div creado, la segunda búsqueda que termine será el segundo div creado, y así sucesivamente.
Si desea mantener constantemente el orden de creación de sus divs, debe eliminarlo de la devolución de llamada de su map porque cada recuperación no espera a que finalice la anterior. Como esto :
for (nuevo of nuevos) { const div = document.createElement('div'); const peticion = await fetch(`http://localhost:51482/api/values/${nuevo[3]}`, { method: 'GET' }); const imagen = await peticion.blob(); const url = URL.createObjectURL(imagen); div.innerHTML = ` <div class="body-card body-card-reci ${nuevo[0]}"> <div class="card-title"> <span>Nuevo</span> </div> <div class="img-card"> <div class="img" style="background-image: url(${url});"></div> </div> <div class="content-card"> <p> <i class="fas fa-tags"></i> ${nuevo[1]} </p> </div> </div> ` noticias_recientes.appendChild(div); }De esta manera, cada recuperación esperará pacientemente a que finalice la anterior y sus divs siempre se crearán en el mismo orden.
Tenga en cuenta que claramente no está optimizado para hacer esto . Porque tus peticiones ya no se hacen en paralelo, sino una tras otra. Entonces, el tiempo de ejecución de esta función será (avgTimeOfFetch) * nbRequestToDo segundos
Si desea algo más optimizado, probablemente debería seguir ejecutando sus solicitudes en paralelo como lo hizo en su versión inicial, luego ordenar los datos de la manera que desee y luego, en ese punto, puede crear sus divs e insertarlos en el DOM.
El orden diferente puede ocurrir porque algunas de las promesas await -ed dentro de las múltiples devoluciones de llamada del map pueden resolverse antes que otras, dando un orden de ejecución diferente.
Puede recuperar los resultados en su orden original utilizando Promise.all , lo que aún permite que las tareas asíncronas que no son JS se ejecuten de forma independiente entre sí:
const promises = nuevos.map(async nuevo => { const div = document.createElement('div'); const peticion = await fetch(`http://localhost:51482/api/values/${nuevo[3]}`, { method: 'GET' }); const imagen = await peticion.blob(); const url = URL.createObjectURL(imagen); div.innerHTML = ` <div class="body-card body-card-reci ${nuevo[0]}"> <div class="card-title"> <span>Nuevo</span> </div> <div class="img-card"> <div class="img" style="background-image: url(${url});"></div> </div> <div class="content-card"> <p> <i class="fas fa-tags"></i> ${nuevo[1]} </p> </div> </div> `; // Don't append to the DOM yet, but *return* return div; }); // Collect the DIVs in the order of the originally fetched data: const divs = await Promise.all(promises); // ...And populate the DOM for (const div of divs) noticias_recientes.appendChild(div);