JS全局"let"变量在功能上没有更新?

qxz*_*qxz 18 javascript google-chrome let requestanimationframe ecmascript-6

编辑:我已将此报告为Chromium错误:https://bugs.chromium.org/p/chromium/issues/detail? id = 668257

我在JS中用可以射击的敌人创建一个小帆布游戏.为了测试,我创建了一个全局声明的标志,let fancy = true;以确定是否使用"花式"定位算法.我这样按下P就会切换这个标志.我的主要功能,每秒frame调用另一个函数autoShoot,五次.autoShoot使用fancy旗帜.

今天,奇怪的事情开始发生了; 我不记得引入了什么变化.有时,当我按下P时,autoShoot表现得像fancy是没有被切换.我做了一些调试和发现新的触发值反映内frame,但autoShoot不更新的价值.它间歇性地发生,有时它的价值autoShoot会自行解决(没有我做过任何事情).

我把代码减少到了以下,这对我来说仍然存在问题.尝试多次按P.对我来说,两个值"不同步"并在按P一次或两次后显示不同:

在我的电脑上按P后的屏幕截图

(我在Windows 10上运行Chrome"Version 54.0.2840.99 m".)

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);
Run Code Online (Sandbox Code Playgroud)
<code>
  fancy (frame)     = <span id="frame"></span><br>
  fancy (autoShoot) = <span id="autoShoot"></span>
</code>
<canvas id="c"></canvas>
Run Code Online (Sandbox Code Playgroud)

到处玩,这里有一些观察:

  • 删除以下任何一项导致问题消失:
    • 处理画布的顶部代码中的任何一行,甚至只是后面的注释const ratio
    • 循环的空... for (let b of bullets) {}
    • 改变let fancy =var fancy =或者只是fancy =
    • 将整个事物放在全局范围之外(通过使用IIFE,onload处理程序或块作用域)
  • 增加bullets阵列的大小会增加问题发生的频率.我认为这是因为它frame需要更长的时间来执行; 最初,bullets.length只有20,但每次循环迭代做了一些东西来更新子弹等.

这会发生在您的计算机上吗?这有什么合理的解释吗?我试过重启我的浏览器,没有变化.

RWA*_*WAM 0

我在 Mac 上使用 Chrome 54.0.2840.98,也会发生这种情况。我认为这是一个范围问题,因为如果我将语句后面的声明包装let到一个{\xe2\x80\xa6}块中,那么该代码片段可以正常工作,并且两个值在按键后立即更改。

\n\n

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

\n

  • 是的,OP确实找到了各种解决方案,可以在玩耍时避免问题,但他要求的是对观察到的行为的解释。 (2认同)