编辑:我已将此报告为Chromium错误:https://bugs.chromium.org/p/chromium/issues/detail?id=668257
我在JS中用可以射击的敌人创建一个小帆布游戏。为了测试,我创建了一个标记,全局声明为let fancy = true;
,以确定是否使用" fancy"定位算法。我这样按下P就会切换这个标志。我的主要功能frame
每秒调用另一个函数autoShoot
五次。 autoShoot
使用fancy
标记。
今天,奇怪的事情开始发生了;我不记得引入了什么变化。有时候,当我按下P时,autoShoot
就像fancy
这样的行为没有被切换。我做了一些调试,发现新的切换值 反映在frame
内,但在autoShoot
中,值未更新。它间歇性地发生,有时autoShoot
中的值会自行修复(没有我做过任何事情)。
我已将代码缩减为以下内容,但仍然存在问题。尝试多次按P。对我来说,这两个值不同步"按P一次或两次后显示不同:
(我正在运行Chrome"版本54.0.2840.99 m"在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);
&#13;
<code>
fancy (frame) = <span id="frame"></span><br>
fancy (autoShoot) = <span id="autoShoot"></span>
</code>
<canvas id="c"></canvas>
&#13;
到处玩,这里有一些观察:
const ratio
之后的评论 for (let b of bullets) {}
let fancy =
更改为var fancy =
或仅fancy =
bullets
数组的大小会增加问题发生的频率。我认为这是因为它使frame
需要更长的时间来执行;最初,bullets.length
只有20,但每次循环迭代都做了一些事情来更新子弹等。这是否会在您的计算机上发生?这有什么合理的解释吗?我尝试重新启动浏览器,没有变化。
答案 0 :(得分:2)
每个人都评论说它似乎是一个Chrome
问题。
我已尝试在Chrome
版本45.0.2454.85 m (64-bit)
和44.0.2403.107 m (32-bit)
上重现相同的问题(当然是启用严格模式),但我没有成功。但是在版本54.0.2840.99 m (64-bit)
上它就在那里。
我注意到将requestAnimationFrame
更改为setInterval
之类的内容也会让问题彻底消失。
因此,我认为这种奇怪的行为与较新版本的Chrome's
requestAnimationFrame
有关,并且可能会阻止let
的范围界定和函数提升。
我无法说出Chrome
的哪个版本我们可以看到这种&#34;错误&#34;,但我可以假设它可以是版本52
,因为在此版本中发生了许多更改,例如Garbage collection
的新方法,对es6
和es7
等的原生支持。有关详细信息,您可以观看this video from I/O 2016
。
也许,新的Garbage collection
方法导致了这个问题,因为正如他们在上面提到的视频中所说的那样,它与浏览器框架相连,类似于v8
的GC会浏览器处于空闲状态,以便不触及帧的绘制等。正如我们所知requestAnimationFrame
是一种在下一帧绘图上调用callback
的方法,也许在这个过程中这些奇怪的事情和#39;发生了。但这只是一个假设,而我没有能力对此说些严肃的事情:)
答案 1 :(得分:0)
我在Mac上使用Chrome 54.0.2840.98,它也会发生。我认为这是一个范围问题,因为如果我将let
语句后面的声明包装到{…}
块中,那么该代码段工作正常,并且在按下键后两个值都会立即更改。
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);
}
&#13;
<code>
fancy (frame) = <span id="frame"></span><br>
fancy (autoShoot) = <span id="autoShoot"></span>
</code>
<canvas id="c"></canvas>
&#13;