Blog

  • Fetch con reintentos y tiempo de espera

    Fetch con reintentos y tiempo de espera

    Solución al problema de la semana pasada, y de paso una función que reintenta las peticiones que fallan y corta las que tardan demasiado.

    export async function pedir(url, { intentos = 3, espera = 5000 } = {}) {
      for (let i = 1; i <= intentos; i++) {
        const control = new AbortController();
        const reloj = setTimeout(() => control.abort(), espera);
        try {
          const r = await fetch(url, { signal: control.signal, cache: 'no-store' });
          if (r.ok) return await r.json();
        } catch (error) {
          if (i === intentos) throw error;
        } finally {
          clearTimeout(reloj);
        }
        await new Promise((listo) => setTimeout(listo, 500 * i));
      }
      throw new Error('Sin respuesta tras ' + intentos + ' intentos');
    }

    La clave era cache: no-store. El servidor de pruebas devolvía max-age=600.

  • Un layout responsive con CSS Grid en veinte líneas

    Un layout responsive con CSS Grid en veinte líneas

    Una cuadrícula de tarjetas que se adapta a cualquier ancho sin una sola media query. El truco está en combinar auto-fit con minmax().

    .tarjetas {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
      gap: 1.5rem;
      padding: 1.5rem;
    }
    
    .tarjeta {
      display: grid;
      grid-template-rows: auto 1fr auto;
      border: 1px solid #ddd;
      border-radius: .5rem;
      overflow: hidden;
    }
    
    .tarjeta img {
      aspect-ratio: 16 / 9;
      object-fit: cover;
      width: 100%;
    }

    Con grid-template-rows: auto 1fr auto, el pie de todas las tarjetas queda alineado aunque el texto tenga longitudes distintas.