¿Es posible crear 2 loops en javascript donde se priorizará un bucle en caso de deficiencia de resources? (Ambos manejan marcas de juego)

El problema es como tal:

En un juego multijugador basado en js y asm.js, tengo dos loops.

Uno maneja los tics reales del juego, como la position de la unidad, la velocidad y el combate.

El otro maneja la representación de este mundo en el canvas para que el usuario lo vea.

Lo que me gustaría que ocurra es que cuando el procesador / GPU (hacen que eso sea lo mismo en algunas máquinas ahora, no puede decir que estoy contento con eso) se sobrecarga demasiado, el ciclo de representación debería omitir y, por lo tanto, dejar de cambiar el lona. Es decir, congelar la pantalla del juego en un lag lucio.

Mientras tanto, la poca potencia de procesamiento que queda se utiliza para completar con éxito el tic del juego real, lo que evita la desynchronization con otros clientes del juego.

(Es un juego parecido a un RTS cuando se trata de cargar, por lo que la input del usuario en lugar de las posiciones de todos los objects se envía a través de la networking).

De lo contrario, el cliente tendría que ser expulsado por los otros clientes o todos los clientes tendrían que hacer una pausa para que se vuelva a conectar y volver a sincronizar. es decir, malo, malo, malo!

Una manera improvisada y descuidada de hacer esto probablemente sería mediante el uso de marcas de time y terminar el ciclo gráfico si no se completa en un time determinado. Uno presumiblemente haría esto determinando el time máximo de ejecución para los types de packages en la stack del bucle e inmediatamente terminaría el bucle si el "time para ejecutar el valor" de todos los packages juntos es demasiado grande para ser tratado dentro de la capacidad del recurso las marcas de time están indicando por medición de desaceleración. Demonios, tal vez eso sea radical, pero tal vez incluso saltee el ciclo gráfico cuando se detecte una desaceleración solo para asegurarse de evitar la desynchronization.

Así que priorizar un bucle sobre otro (ambos manejando tics) y hacer que el segundo salte si se detecta una escasez de resources para garantizar que el primero siempre complete su tic dentro de cada intervalo de time (10 tics por segundo aquí).

¿Alguna posibilidad o método de mejores prácticas que puedan informarme?

EDITAR: Por favor, concéntrese en la capacidad de medir la disponibilidad de los resources de la CPU y la omisión / terminación por un tic del bucle gráfico si estos resources no estuvieran disponibles para terminar ambos loops (es decir, si los loops no finalizarán en el marco de time de 100 ms después que el próximo tic del bucle ya debería estar disparando, no inicie / termine el bucle de charts).

Una solución sería utilizar un trabajador web para hacer su bucle de actualización mundial y luego el bucle de javascript normal para hacer el renderizado. Necesitaría entregar el estado de manera directa del empleado web, pero el ciclo de representación solo se basaría en los datos actualizados.

Una ventaja es que aún podría tener un código de visualización reactjsrio en el bucle ui principal.

Esto también tiene la ventaja del hecho de que el trabajador web podría estar usando un núcleo diferente y con múltiples trabajadores de la web podría usar múltiples núcleos adicionales.

Para el bucle lógico, tomaría setInterval , y para la pintura – requestAnimationFrame . Y aún más: la callback en requestAnimationFrame también recibe una timestamp, por lo que puede realizar un seguimiento de las marcas de time y saltear un solo cuadro si aparece alguna falta.


el procesador puede manejar otras tareas mientras también renderiza la animation

Esta afirmación es incorrecta: el procesador solo puede manejar una tarea, y requestAnimationFrame no es realmente el Rendering, es su callback, javascript genérico. Puedes pensarlo como un setTimeout . La única diferencia es que intenta ejecutar la callback en el siguiente fotogtwig de fotogtwigs libre. Es por eso que es mucho mejor que setTimeout . Entonces, para las animaciones debe usar requestAnimationFrame . Otra buena parte es cuando la página web está en segundo plano (se abre otra pestaña ). Entonces no se llamará a la callback hasta que llegue al primer plano. Esto ahorra time de procesador, ya que no se calcula nada en esa callback.

Volviendo a su pregunta: Ahora pero, que solo se puede procesar una callback en un time, por lo que si el procesador está en un momento particular ocupado con la function lógica, entonces la callback del ciclo de animation no se disparará. En ese caso, llama 'lag'. Pero, como entendí, en realidad es el comportamiento deseado: dar más time a la function de callback lógica. Pero hay otro lado. ¿Qué ocurre si la function de animation está ocupada cuando se dispara el time de la function lógica? En este caso, se disparará solo cuando finalice la function de animation. No hay nada que hacer al respecto. Si su function de animation es "pesada", solo podría intentar dividirla en 2 cuadros. Un cuadro: prepare todo para renderizar, el segundo, renderice.

Pero de todos modos, nunca se convierte en un intervalo milisegundo perfecto o time de espera en javascript. Como quiera que se llame hasta que event-loop no sea libre. Para tener la idea:

 var seconds = 0; setInterval(function(){ seconds++; var x = 10e8; while(--x); }, 1000); 

Depende de su CPU, pero después de 10 segundos de time, la variable 'segundos' será mucho menor que 10.

Y una cosa más, si realmente confías en el time, entonces es más seguro usar Date.now () para sincronizar el siguiente tick lógico:

 var setLogicalLoop = (function(){ var _startedAt, _stop, _ms; function frame(){ if (_stop === true) return; // calculations var dt = Date.now() - _startedAt, diff = dt % _ms; setTimeout(frame, ms - diff); }; return function (callback, ms){ _startedAt = Date.now(); _stop = false; setTimeout(frame, ms); return function(){ _stop = true; }; }; }); // -> start var stopLoop = setLogicalLoop(myFunction, ms); // -> stop stopLoop();