Tengo un setInterval
código de ejecución 30 veces por segundo. Esto funciona muy bien, sin embargo, cuando selecciono otra pestaña (para que la pestaña con mi código se vuelva inactiva), setInterval
se establece en un estado inactivo por alguna razón.
Hice este caso de prueba simplificado ( http://jsfiddle.net/7f6DX/3/ ):
var $div = $('div');
var a = 0;
setInterval(function() {
a++;
$div.css("left", a)
}, 1000 / 30);
Si ejecuta este código y luego cambia a otra pestaña, espere unos segundos y regrese, la animación continúa en el punto en que estaba cuando cambió a la otra pestaña. Por lo tanto, la animación no se ejecuta 30 veces por segundo en caso de que la pestaña esté inactiva. Esto puede confirmarse contando la cantidad de veces setInterval
que se llama a la función cada segundo; no será 30 sino solo 1 o 2 si la pestaña está inactiva.
Supongo que esto se hace por diseño para mejorar el rendimiento, pero ¿hay alguna forma de desactivar este comportamiento? En realidad es una desventaja en mi escenario.
fuente
Date
objeto para ver realmente qué tiempo ha pasado.Date
. De modo que cuando los intervalos no se disparan rápidamente (por esta u otras razones), la animación se vuelve más brusca, no más lenta.Respuestas:
En la mayoría de los navegadores, las pestañas inactivas tienen una ejecución de baja prioridad y esto puede afectar a los temporizadores de JavaScript.
Si los valores de su transición se calcularon usando el tiempo real transcurrido entre fotogramas en lugar de incrementos fijos en cada intervalo, no solo soluciona este problema, sino que también puede lograr una animación más suave utilizando requestAnimationFrame, ya que puede obtener hasta 60 fps si el procesador no está muy ocupado.
Aquí hay un ejemplo de JavaScript vainilla de una transición de propiedad animada usando
requestAnimationFrame
:Para tareas en segundo plano (no relacionadas con la IU)
Comentario de @UpTheCreek:
Si usted tiene tareas en segundo plano que las necesidades a ser ejecutadas con precisión a intervalos determinados, puede utilizar Trabajadores Web HTML5 . Eche un vistazo a la respuesta de Möhre a continuación para obtener más detalles ...
CSS vs JS "animaciones"
Este problema y muchos otros podrían evitarse utilizando transiciones / animaciones CSS en lugar de animaciones basadas en JavaScript, lo que agrega una sobrecarga considerable. Recomiendo este complemento jQuery que le permite aprovechar las transiciones CSS al igual que los
animate()
métodos.fuente
before = now;
para obtener el tiempo transcurrido desde el inicio en lugar del final de la llamada anterior. Esto suele ser lo que quieres al animar cosas. Tal como está ahora, si una ejecución de la función de intervalo dura 15 ms,elapsedTime
dará 35 ms (en lugar de 50 ms, que es el intervalo) la próxima vez que se llame (cuando la pestaña está activa).Me encontré con el mismo problema con el desvanecimiento de audio y el reproductor HTML5. Se quedó atascado cuando la pestaña quedó inactiva. Entonces descubrí que un WebWorker puede usar intervalos / tiempos de espera sin limitación. Lo uso para publicar "ticks" en el javascript principal.
Código de WebWorkers:
Javascript principal:
fuente
Hay una solución para usar Web Workers (como se mencionó anteriormente), porque se ejecutan en un proceso separado y no se ralentizan
He escrito un pequeño script que puede usarse sin cambios en su código; simplemente anula las funciones setTimeout, clearTimeout, setInterval, clearInterval.
Solo inclúyalo antes de todo su código.
Más información aquí
fuente
Solo haz esto:
Las pestañas inactivas del navegador almacenan algunas de las funciones
setInterval
osetTimeout
.stop(true,true)
detendrá todos los eventos almacenados en el búfer y ejecutará inmediatamente solo la última animación.El
window.setTimeout()
método ahora se sujeta para enviar no más de un tiempo de espera por segundo en pestañas inactivas. Además, ahora sujeta los tiempos de espera anidados al valor más pequeño permitido por la especificación HTML5: 4 ms (en lugar de los 10 ms a los que solía sujetar).fuente
Creo que una mejor comprensión de este problema es en este ejemplo: http://jsfiddle.net/TAHDb/
Estoy haciendo algo simple aquí:
Tenga un intervalo de 1 segundo y cada vez oculte el primer intervalo y muévalo al último, y muestre el segundo intervalo.
Si permanece en la página, funciona como se supone. Pero si oculta la pestaña durante unos segundos, cuando regrese verá algo cansado.
Es como si todos los eventos que no ocurrieron durante el tiempo que estuvo inactivo ahora ocurran todo en 1 vez. así que por unos segundos obtendrás como X eventos. son tan rápidos que es posible ver los 6 tramos a la vez.
Por lo tanto, parece que Chrome solo retrasa los eventos, por lo que cuando regrese, todos los eventos ocurrirán, pero todos a la vez ...
Esto fue una aplicación práctica para una presentación de diapositivas simple. Imagine que los números son Imágenes, y si el usuario permanece con la pestaña oculta cuando regresó, verá todas las imágenes flotando, Totalmente malladas.
Para arreglar esto, use la parada (verdadero, verdadero) como pimvdb dijo. Esto borrará la cola del evento.
fuente
requestAnimationFrame
que jQuery se utiliza. Debido a algunas peculiaridades que tenía (como esta), lo eliminaron. En 1.7 no ves este comportamiento. jsfiddle.net/TAHDb/1 . Debido a que el intervalo es de una vez por segundo, esto en realidad no afecta el problema que publiqué, ya que el máximo para pestañas inactivas también es una vez por segundo, por lo que no hay diferencia.Para mí no es importante reproducir audio en segundo plano como para otros aquí, mi problema era que tenía algunas animaciones y actuaban como locos cuando estabas en otras pestañas y volvías a ellas. Mi solución fue poner estas animaciones dentro si eso impide la pestaña inactiva :
gracias a eso mi animación se estaba ejecutando solo si la pestaña estaba activa. Espero que esto ayude a alguien con mi caso.
fuente
setInterval(() => !document.hidden && myfunc(), 1000)
y funciona perfectamenteAmbos
setInterval
yrequestAnimationFrame
no funcionan cuando la pestaña está inactiva o funciona pero no en los períodos correctos. Una solución es usar otra fuente para eventos de tiempo. Por ejemplo, los sockets web o los trabajadores web son dos orígenes de eventos que funcionan bien mientras la pestaña está inactiva. Por lo tanto, no es necesario mover todo su código a un trabajador web, solo use el trabajador como fuente de eventos de tiempo:.
Enlace jsfiddle de esta muestra.
fuente
Fuertemente influenciado por la biblioteca de Ruslan Tushov, he creado mi propia biblioteca pequeña . Simplemente agregue el script en el
<head>
y se parchearásetInterval
ysetTimeout
con los que usanWebWorker
.fuente
Reproducir un archivo de audio garantiza el rendimiento completo de Javascript de fondo por el momento
Para mí, fue la solución más simple y menos intrusiva: aparte de reproducir un sonido débil / casi vacío, no hay otros posibles efectos secundarios
Puede encontrar los detalles aquí: https://stackoverflow.com/a/51191818/914546
(De otras respuestas, veo que algunas personas usan diferentes propiedades de la etiqueta de audio, me pregunto si es posible usar la etiqueta de audio para un rendimiento completo, sin tener que reproducir algo)
fuente
Nota: esta solución no es adecuada si desea que su intervalo funcione en segundo plano, por ejemplo, reproduciendo audio o ... pero si está confundido, por ejemplo, acerca de que su animación no funciona correctamente cuando regresa a su página (pestaña), esto es Una buena solución.
Hay muchas maneras de lograr este objetivo, tal vez el "WebWorkers" es el más estándar, pero ciertamente no es el más fácil y práctico, especialmente si no tiene suficiente tiempo, así que puede intentarlo de esta manera:
► CONCEPTO BÁSICO:
1- construya un nombre para su intervalo (o animación) y configure su intervalo (animación), para que se ejecute cuando el usuario abra su página por primera vez:
var interval_id = setInterval(your_func, 3000);
2- por
$(window).focus(function() {});
y$(window).blur(function() {});
puedeclearInterval(interval_id)
cada vez que el navegador (pestaña) esté desactivado y vuelva a ejecutar su intervalo (animación) cada vez que el navegador (pestaña) actúe nuevamenteinterval_id = setInterval();
► CÓDIGO DE EJEMPLO:
fuente
Es una pregunta bastante antigua, pero encontré el mismo problema.
Si ejecuta su web en Chrome, puede leer esta publicación Pestañas de fondo en Chrome 57 .
Básicamente, el temporizador de intervalos podría ejecutarse si no se ha agotado el presupuesto del temporizador.
El consumo de presupuesto se basa en el uso del tiempo de CPU de la tarea dentro del temporizador.
Según mi escenario, dibujo videos en el lienzo y los transporto a WebRTC.
La conexión de video webrtc seguiría actualizándose incluso si la pestaña está inactiva.
Sin embargo, tienes que usar en
setInterval
lugar derequestAnimationFrame
.Sin embargo, no se recomienda para la representación de la interfaz de usuario.
Sería mejor escuchar
visibilityChange
evento y cambiar el mechenismo en consecuencia.Además, puedes probar @ kaan-soral y debería funcionar según la documentación.
fuente
Aquí está mi solución aproximada
fuente
postMessageHandler
invoca su propio evento se está manejando, teniendo así un bucle infinito que no está bloqueando la interfaz de usuario. Y mientras está en bucle infinito, está comprobando con cada gestión de eventos si hay una función de tiempo de espera o intervalo para ejecutar.Pude llamar a mi función de devolución de llamada a un mínimo de 250 ms usando la etiqueta de audio y manejando su evento ontimeupdate. Se llama 3-4 veces en un segundo. Es mejor que un segundo conjunto de retraso
fuente