Volver
Ctrl+Space
◑
Copiar
Descargar
Restaurar
Ejecutar
Ctrl+Enter
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <title>Fetch API — Ejemplo 3</title> <style> body { font-family: Arial, sans-serif; padding: 20px; background: #fff; max-width: 660px; } h3 { margin: 22px 0 8px; font-size: 15px; color: #333; } button { padding: 8px 18px; background: #F7DF1E; border: none; border-radius: 6px; font-weight: bold; cursor: pointer; font-size: 14px; margin: 4px 4px 4px 0; transition: background 0.15s; } button:hover { background: #e6cc00; } button:disabled { background: #eee; color: #aaa; cursor: not-allowed; } .estado { padding: 10px 14px; border-radius: 6px; font-size: 13px; font-family: monospace; margin-top: 10px; } .estado.loading { background: #fffde7; border: 1px solid #F7DF1E; color: #856404; } .estado.ok { background: #f0fdf4; border: 1px solid #86efac; color: #166534; } .estado.err { background: #fef2f2; border: 1px solid #fca5a5; color: #991b1b; } .tiempo { display: inline-block; background: #1a1a1a; color: #F7DF1E; font-family: monospace; font-size: 13px; padding: 4px 12px; border-radius: 5px; margin-top: 6px; } .card { border: 1px solid #eee; border-radius: 8px; padding: 12px 16px; margin-top: 8px; background: #fafafa; } .card h4 { margin: 0 0 6px; color: #333; font-size: 14px; } .card p { margin: 2px 0; font-size: 12px; color: #666; } .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 8px; } .badge { display: inline-block; font-size: 11px; font-weight: bold; padding: 2px 9px; border-radius: 10px; margin-left: 6px; } .badge-ok { background: #d1fae5; color: #065f46; } .badge-mal { background: #fee2e2; color: #991b1b; } .log { background: #f9f9f9; border: 1px solid #eee; border-radius: 6px; padding: 8px 12px; font-family: monospace; font-size: 12px; max-height: 130px; overflow-y: auto; margin-top: 10px; } .log div { padding: 2px 0; } .log .ok-log { color: #166534; } .log .err-log { color: #991b1b; } </style> </head> <body> <h2>Fetch API — Peticiones en paralelo</h2> <h3>1. Secuencial vs Paralelo — Promise.all()</h3> <p style="font-size:13px;color:#555;"> Traemos un usuario y sus posts. Primero uno por uno (secuencial), después con <code>Promise.all()</code> (paralelo) — mirá la diferencia de tiempo. </p> <button id="btnSecuencial">Cargar secuencial</button> <button id="btnParalelo">Cargar en paralelo</button> <div id="resultadoTiempos"></div> <div id="datosCargados"></div> <h3>2. Promise.allSettled() — cuando una petición puede fallar</h3> <p style="font-size:13px;color:#555;"> Lanzamos 3 peticiones a la vez. Una de ellas apunta a un endpoint que no existe. Con <code>Promise.all()</code> una falla y se pierden las otras dos. Con <code>Promise.allSettled()</code> esperamos a todas, sin importar el resultado. </p> <button id="btnAllSettled">Probar Promise.allSettled()</button> <div class="log" id="logSettled">Esperando...</div> <script> // Fetch API en JavaScript - Ejemplo 3: Peticiones en paralelo const BASE = "https://jsonplaceholder.typicode.com"; function setEstado(contenedor, tipo, texto) { contenedor.innerHTML = `<div class="estado ${tipo}">${texto}</div>`; } // ── 1. Secuencial ───────────────────────────────────────────────────── document.getElementById("btnSecuencial").addEventListener("click", async function() { const divTiempo = document.getElementById("resultadoTiempos"); const divDatos = document.getElementById("datosCargados"); this.disabled = true; setEstado(divTiempo, "loading", "⏳ Cargando secuencial (uno espera al otro)..."); divDatos.innerHTML = ""; const inicio = performance.now(); // Cada await espera a que termine el anterior antes de seguir const usuario = await fetch(`${BASE}/users/1`).then(r => r.json()); const posts = await fetch(`${BASE}/users/1/posts`).then(r => r.json()); const ms = Math.round(performance.now() - inicio); setEstado(divTiempo, "ok", `✅ Secuencial completado`); divTiempo.innerHTML += `<div class="tiempo">⏱️ ${ms} ms</div>`; divDatos.innerHTML = ` <div class="card"> <h4>${usuario.name}</h4> <p>${usuario.email} — ${posts.length} posts</p> </div>`; this.disabled = false; }); // ── 1. Paralelo con Promise.all ────────────────────────────────────── document.getElementById("btnParalelo").addEventListener("click", async function() { const divTiempo = document.getElementById("resultadoTiempos"); const divDatos = document.getElementById("datosCargados"); this.disabled = true; setEstado(divTiempo, "loading", "⏳ Cargando en paralelo (las dos a la vez)..."); divDatos.innerHTML = ""; const inicio = performance.now(); // Promise.all lanza las dos peticiones al mismo tiempo const [usuario, posts] = await Promise.all([ fetch(`${BASE}/users/1`).then(r => r.json()), fetch(`${BASE}/users/1/posts`).then(r => r.json()), ]); const ms = Math.round(performance.now() - inicio); setEstado(divTiempo, "ok", `✅ Paralelo completado`); divTiempo.innerHTML += `<div class="tiempo">⏱️ ${ms} ms</div>`; divDatos.innerHTML = ` <div class="card"> <h4>${usuario.name}</h4> <p>${usuario.email} — ${posts.length} posts</p> </div>`; this.disabled = false; }); // ── 2. Promise.allSettled ──────────────────────────────────────────── function agregarLog(mensaje, tipo) { const log = document.getElementById("logSettled"); const div = document.createElement("div"); div.className = tipo === "ok" ? "ok-log" : "err-log"; div.textContent = mensaje; if (log.firstChild && log.firstChild.textContent === "Esperando...") log.innerHTML = ""; log.insertBefore(div, log.firstChild); } document.getElementById("btnAllSettled").addEventListener("click", async function() { this.disabled = true; document.getElementById("logSettled").innerHTML = ""; agregarLog("⏳ Lanzando 3 peticiones (una va a fallar a propósito)...", "ok"); const peticiones = [ fetch(`${BASE}/posts/1`).then(r => r.json()), fetch(`${BASE}/posts/99999999`).then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); }), fetch(`${BASE}/posts/2`).then(r => r.json()), ]; const resultados = await Promise.allSettled(peticiones); resultados.forEach((resultado, i) => { if (resultado.status === "fulfilled") { agregarLog(`✅ Petición #${i + 1}: OK — "${resultado.value.title.slice(0, 30)}..."`, "ok"); } else { agregarLog(`❌ Petición #${i + 1}: falló — ${resultado.reason.message}`, "err"); } }); agregarLog(`— Terminaron las 3, ninguna bloqueó a las demás —`, "ok"); this.disabled = false; }); </script> </body> </html>