16 puntos por GN⁺ 2025-09-22 | Aún no hay comentarios. | Compartir por WhatsApp
  • En JavaScript, setTimeout(0) en realidad no se ejecuta de inmediato, y muchas veces se retrasa al menos 4 ms; esta es una limitación predeterminada del navegador para evitar abusos
  • Estas restricciones buscan impedir que los sitios web abusen indiscriminadamente de los temporizadores y provoquen consumo de batería o degradación de la interacción; en modo de batería puede limitarse a 16 ms y en pestañas en segundo plano incluso a 1 segundo
  • Para sortear las limitaciones de setTimeout, los desarrolladores han usado diversas APIs alternativas de temporización como setImmediate, MessageChannel.postMessage, window.postMessage y scheduler.postTask
  • Según los benchmarks reales, Chrome y Firefox aplican el límite de 4 ms, pero MessageChannel y scheduler.postTask funcionan casi sin demora, mientras que Safari se caracteriza por restringir setTimeout de forma más agresiva
  • En el fondo, se trata de un equilibrio entre proteger la experiencia del usuario y la libertad del desarrollador; hoy la Scheduler API se está consolidando como la solución estandarizada, aunque si hay abusos también podrían introducirse nuevas intervenciones del navegador (Intervention)

Contexto de la limitación de setTimeout

  • Incluso con setTimeout(0), por el abuso muchas veces la ejecución real ocurre al menos 4 ms después
    const start = performance.now()  
    setTimeout(() => {  
      // se ejecuta después de unos 4 ms  
      console.log(performance.now() - start)  
    }, 0)  
    
  • Esto busca frenar las llamadas repetitivas indiscriminadas para reducir el consumo de batería y los retrasos de renderizado
  • Algunos navegadores endurecen la restricción según el entorno
    • Modo batería: 16 ms en Edge antiguo
    • Pestaña en segundo plano: hasta 1 segundo de retraso en Chrome

Aparición de otras APIs de temporización

  • setImmediate: solo compatible con IE y Edge antiguo; en la práctica está obsoleta
  • MessageChannel.postMessage: envía tareas al event loop mediante un canal separado
  • window.postMessage: tiene buen rendimiento, pero existe riesgo de conflicto con otros scripts
  • scheduler.postTask: compatible con navegadores modernos y considerado la opción más estable

Resultados del benchmark (MacBook Pro 2021, 101 iteraciones)

  • Chrome 139: setTimeout 4.2 ms, scheduler.postTask 0 ms
  • Firefox 142: setTimeout 4.72 ms, scheduler.postTask 0.01 ms
  • Safari 18.4: setTimeout 26.73 ms, MessageChannel 0.52 ms, window.postMessage 0.05 ms

Caso de fake-indexeddb

  • IndexedDB quiere hacer commit automático de las transacciones justo después de que terminen las microtareas del event loop
  • En Node.js, setImmediate es ideal, pero en el navegador setTimeout resulta ineficiente
  • En Chrome, una tarea que toma 300 ms en Node puede alargarse hasta 4.8 segundos en el navegador
  • Como solución, se usa scheduler.postTask por defecto y se adoptan MessageChannel/window.postMessage como fallback por compatibilidad

Debate sobre la intervención del navegador

  • Un lado sostiene que hay que limitar los temporizadores para que los desarrolladores estén protegidos de sí mismos
  • El otro lado sostiene que debe garantizarse la libertad para que los desarrolladores puedan medir y optimizar por su cuenta
  • Al final, siguiendo el principio de priorizar al usuario, el navegador interviene para evitar abusos
  • La Scheduler API busca conciliar ambas posturas, dando a los desarrolladores control detallado sobre las tareas mientras se alinea con el pipeline de renderizado del navegador

Perspectivas a futuro

  • Parece que postTask y postMessage seguirán sin throttling por un tiempo
  • Pero si se abusan prioridades altas como user-blocking, podría volver a haber intervención
  • A largo plazo, quizá haga falta otra API alternativa como scheduler2

Aún no hay comentarios.

Aún no hay comentarios.