Tengo un componente que "carga perezosamente" algunos comentarios, en un intervalo de 100 ms.
Cuando uso setTimeout, es muy lento.
componente
<div *ngFor="let post of posts"> <app-post [post]="post" ></app-post> </div>Esto hace que mi aplicación sea lenta (promedio de fps 14, tiempo de inactividad 51100ms):
while(this.postService.hasPosts()){ setTimeout(()=> { this.posts.push(this.postService.next(10)); },100); }Esto hace que mi aplicación sea fluida (promedio de fps 35, tiempo de inactividad 40800ms)
while(this.postService.hasPosts()){ timer(100).subscribe(()=> { this.posts.push(this.postService.next(10)); }); }¿Hay alguna explicación, por qué el temporizador rxjs funciona mucho mejor?
Hice un análisis de tiempo de ejecución con firefox. En el primer ejemplo, la velocidad de fotogramas cae a 14 fps. En el otro ejemplo, 35 fps.
Incluso el tiempo de inactividad es un 20% menor.
Este método es aún más suave (promedio de fps 45, tiempo de inactividad 13500ms):
interval(100).pipe(takeWhile(this.postService.hasPosts()).subscribe(()=> { this.posts.push(this.postService.next(10)); }); }Tu última solución es la única correcta.
Las otras dos soluciones no deberían funcionar como usted esperaba que funcionaran. En realidad, esto debería resultar en un bucle infinito.
Esto se debe a cómo funciona el bucle de eventos de JavaScript . La siguiente imagen muestra un modelo del tiempo de ejecución de JavaScript (la imagen fue tomada de aquí ):
Las partes relevantes para nosotros son la stack y la queue . Un tiempo de ejecución de JavaScript procesa los mensajes en la queue . Cada mensaje está asociado con una función que se llama a medida que se procesa el mensaje.
Para la pila, cada llamada de función crea un marco en la pila que contiene los argumentos de las funciones y las variables locales. Si una función llama a otra función, se coloca un nuevo marco en la parte superior de la pila. Cuando una función devuelve el cuadro superior se saca de la pila.
Ahora, si la pila está vacía, el tiempo de ejecución de JavaScript procesará el siguiente mensaje en la queue (el más antiguo).
Si usa setTimeout(() => doSomething(),100) , la función doSomething() se agrega a la cola después de 100 milisegundos. Esta es la razón por la cual los 100 milisegundos no son un tiempo garantizado sino un tiempo mínimo. Por lo tanto, su doSomething method solo se llama si la pila está vacía y no hay nada más en la cola.
Pero como está iterando en un ciclo while y su condición depende del código dentro de su setTimeout , ha creado un ciclo infinito porque la pila no se vaciará y, por lo tanto, su this.posts.push(this.postService.next(10)); el código nunca será llamado.
Para las implementaciones de RxJS, lo mismo es cierto. Usan programadores para manejar el tiempo. Hay diferentes implementaciones internas del programador en RxJS, pero como podemos ver en las implementaciones para el interval y el timer , si no especificamos un programador, el predeterminado es asyncScheduler. Los horarios de asyncScheduler funcionan con setInterval , que funciona como setTimeout mencionado anteriormente, y envía otro mensaje a la cola.
Probé sus dos soluciones con el bucle while y, de hecho, la primera congeló por completo mi navegador, mientras que la segunda estaba muy retrasada pero podía enviar algo a la consola dentro del bucle while. En realidad, no sé por qué el segundo es un poco más eficaz, pero, sin embargo, ninguno de los dos es lo que realmente quieres. Ya se le ocurrió una buena solución y espero que esta respuesta pueda ayudarlo a comprender por qué las primeras soluciones funcionan tan mal.