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 =
avar fancy =
o simplementefancy =
- poner todo fuera del ámbito global (mediante el uso de IIFE, el controlador onload o el ámbito de bloque)
- cualquier línea en el código en la parte superior que trata el lienzo, incluso solo el comentario después de la
- 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 elframe
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>