- 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
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.