variable template pasar encrypt algoritmo javascript google-chrome ecmascript-6 requestanimationframe let

javascript - template - rsa encryption js



¿La variable global "let" de JS no se actualiza en la función? (2)

Edición: informé esto como un error de Chromium: https://bugs.chromium.org/p/chromium/issues/detail?id=668257

Estoy creando un pequeño juego de lona en JS con enemigos que pueden disparar. Para las pruebas, creé una bandera, declarada globalmente como let fancy = true; , para determinar si usar o no un algoritmo de segmentación "elegante". Lo hice para que al presionar P se alterne esta bandera. Mi función principal, frame , llama a otra función, autoShoot , cinco veces por segundo. autoShoot utiliza la bandera de fancy .

Hoy, algo extraño comenzó a suceder; No recuerdo qué cambio lo introdujo. A veces, cuando autoShoot P, la función autoShoot actúa como si la fancy no hubiera sido activada. Hice algo de depuración y descubrí que el nuevo valor alternado se refleja dentro del frame , pero en autoShoot , el valor no se actualiza. Ocurre de manera intermitente, y algunas veces el valor en autoShoot se arregla solo (sin que yo haya hecho nada).

He reducido el código a lo siguiente, que todavía presenta el problema para mí. Intente presionar P un montón de veces. Para mí, los dos valores se "desincronizan" y se muestran de forma diferente después de presionar P solo una o dos veces:

(Estoy ejecutando Chrome "Versión 54.0.2840.99 m" en Windows 10.)

const canvas = document.getElementById("c"); const width = 0; const height = 0; const ctx = canvas.getContext("2d"); const ratio =1;// (window.devicePixelyRatio||1)/(ctxFOOOOOOOOFOOOOOOOOOFOOOOO||1); canvas.width = width*ratio; canvas.height = height*ratio; canvas.style.width = width+"px"; canvas.style.height = height+"px"; ctx.scale(ratio, ratio); function testSet(id, val) { console.log(id+": "+val); document.getElementById(id).innerText = val; } let fancy = true; document.body.addEventListener("keydown", function(e) { if (e.keyCode == 80) { fancy = !fancy; console.log("Set fancy to: "+fancy); } }); let bullets = Array(2000); let lastTime = 0, shotTimer = 0; function frame(time) { const dt = (time - lastTime)/1000; lastTime = time; if ((shotTimer -= dt) <= 0) { testSet("frame", fancy); autoShoot(); shotTimer = 0.2; } for (let b of bullets) {} requestAnimationFrame(frame); } function autoShoot() { testSet("autoShoot", fancy); } requestAnimationFrame(frame);

<code> fancy (frame) = <span id="frame"></span><br> fancy (autoShoot) = <span id="autoShoot"></span> </code> <canvas id="c"></canvas>

Jugando alrededor, aquí hay algunas observaciones:

  • al eliminar cualquiera de las siguientes causas, el problema desaparece:
    • cualquier línea en el código en la parte superior que trata el lienzo, incluso solo el comentario después de la const ratio
    • el vacío para ... de loop: for (let b of bullets) {}
    • cambiando let fancy = a var fancy = o simplemente fancy =
    • poner todo fuera del ámbito global (mediante el uso de IIFE, el controlador onload o el ámbito de bloque)
  • Aumentar el tamaño de la matriz de bullets aumenta la frecuencia con la que se produce el problema. Creo que es porque hace que el frame tarde más en ejecutarse; originalmente, bullets.length era solo 20, pero cada iteración de bucle hacía algunas cosas para actualizar la viñeta, etc.

¿Ocurre esto en sus computadoras? ¿Hay alguna explicación lógica para esto? He intentado reiniciar mi navegador, sin cambios.


Como todos comentaron, parece ser un problema de Chrome .

He intentado reproducir el mismo problema en Chrome versión 45.0.2454.85 m (64-bit) y 44.0.2403.107 m (32-bit) (habilitando el modo estricto, por supuesto), pero no lo he logrado. Pero en la versión 54.0.2840.99 m (64-bit) está ahí.

Y me di cuenta de que cambiar requestAnimationFrame a algo como setInterval también hace que el problema desaparezca por completo.

Por lo tanto, asumo que este extraño comportamiento tiene algo que ver con Chrome''s requestAnimationFrame Chrome''s en las versiones más recientes, y tal vez bloquee la naturaleza de alcance de let y la elevación de funciones.

No puedo decir de qué versión de Chrome podemos ver este tipo de "error", pero puedo asumir que puede ser la versión 52 , porque en esta versión se produjeron muchos cambios, como el nuevo método de Garbage collection de Garbage collection , soporte nativo para es6 y es7 etc. Para obtener más información, puede ver este video de I/O 2016 .

Tal vez , el nuevo método de Garbage collection está causando este problema, porque como se indicó en el video mencionado anteriormente, está conectado con los marcos del navegador, algo como v8 hace GC cuando el navegador está inactivo, para no tocar el dibujo de los marcos, etc. Como sabemos, requestAnimationFrame es un método que llama a una callback de callback en el siguiente dibujo de marco, tal vez en este proceso ocurran estas cosas extrañas. Pero esto es solo una suposición y no tengo competencia para decir algo serio sobre esto :)


Estoy en Chrome 54.0.2840.98 en Mac y también sucede. Creo que es un problema de alcance, porque si encierro la declaración que sigue a la instrucción let en un bloque {…} , el fragmento funciona bien y ambos valores cambian inmediatamente después de presionar una tecla.

const canvas = document.getElementById("c"); const width = 0; const height = 0; const ctx = canvas.getContext("2d"); const ratio =1;// (window.devicePixelyRatio||1)/(ctxFOOOOOOOOFOOOOOOOOOFOOOOO||1); canvas.width = width*ratio; canvas.height = height*ratio; canvas.style.width = width+"px"; canvas.style.height = height+"px"; ctx.scale(ratio, ratio); function testSet(id, val) { console.log(id+": "+val); document.getElementById(id).innerText = val; } let fancy = true; { document.body.addEventListener("keydown", function(e) { if (e.keyCode == 80) { fancy = !fancy; console.log("Set fancy to: "+fancy); } }); let bullets = Array(2000); let lastTime = 0, shotTimer = 0; function frame(time) { const dt = (time - lastTime)/1000; lastTime = time; if ((shotTimer -= dt) <= 0) { testSet("frame", fancy); autoShoot(); shotTimer = 0.2; } for (let b of bullets) {} requestAnimationFrame(frame); } function autoShoot() { testSet("autoShoot", fancy); } requestAnimationFrame(frame); }

<code> fancy (frame) = <span id="frame"></span><br> fancy (autoShoot) = <span id="autoShoot"></span> </code> <canvas id="c"></canvas>