Javascript 防止运行setTimeout的递归函数复合
我用JavaScript编写了一个Chip-8浏览器,并制作了一个可玩的浏览器版本 它包含一个HTML选择:Javascript 防止运行setTimeout的递归函数复合,javascript,node.js,recursion,browser,settimeout,Javascript,Node.js,Recursion,Browser,Settimeout,我用JavaScript编写了一个Chip-8浏览器,并制作了一个可玩的浏览器版本 它包含一个HTML选择: 庞 俄罗斯方块 每次选择一个ROM时,从文件加载一个ROM: document.querySelector('select')。addEventListener('change',event=>{ 常量rom=event.target.value loadRom(rom) }) 这个loadRom函数获取ROM,将其转换为有用的形式,并将其加载到CPU类的实例中。cpu有一个fet
庞
俄罗斯方块
每次选择一个ROM时,从文件加载一个ROM:
document.querySelector('select')。addEventListener('change',event=>{
常量rom=event.target.value
loadRom(rom)
})
这个loadRom
函数获取ROM,将其转换为有用的形式,并将其加载到CPU类的实例中。cpu
有一个fetch-decode-execute循环,该循环通过step()
调用。我创建了这个cycle
(main)函数来在setTimeout中调用自己
const loadRom=async rom=>{
const response=wait fetch(`./roms/${rom}`)
const arrayBuffer=wait response.arrayBuffer()
const uint8View=新的Uint8Array(arrayBuffer);
const romBuffer=新的romBuffer(uint8View)
cpu.interface.clearDisplay()
cpu.load(romBuffer)
设定时器=0
异步函数循环(){
计时器++
如果(计时器%5==0){
cpu.tick()
计时器=0
}
等待cpu。步骤()
设置超时(周期,3)
}
循环()
}
这很好,直到我用select加载一个新的ROM。现在,这种循环变得复杂,游戏速度提高了一倍。每次你加载一个新的ROM,它会再次合成并创建一个新的循环
如何创建一个无限循环,但停止它并启动一个全新的循环而不使其复合?首先,将当前超时设置为一个持久变量,然后在调用
loadRom
之前调用clearTimeout
。如果还没有加载任何内容,则clearTimeout
将不会执行任何操作
但是由于您还有await
s,您需要检查在await
s运行时是否加载了新的rom。实现这一点的一种方法是使用另一个持久变量,即当前使用的romBuffer
——如果它与函数闭包中的romBuffer
不同,则另一个rom已启动,因此立即返回(不要递归创建超时)
尝试使用
setInerval
并跟踪手柄
然后在加载新的(或相同的)rom时清除它
我很尴尬,事情这么简单,我没有想到。非常感谢。一旦它允许我,我会接受答案。从头开始,它似乎是有效的,但如果在改变之前,循环被卡在承诺中,速度将继续增加。哦,好的一点-你可以跟踪当前的
romBuffer
,如果它在等待期间改变,不要调用setTimeout
,不幸的是,这并不能解决问题,但问题超出了我的问题范围(我需要取消一个正在运行的承诺),因此我会接受它,因为它对我提出的问题是正确的。
let timeout;
let currentRomBuffer;
const loadRom = async rom => {
const response = await fetch(`./roms/${rom}`)
const arrayBuffer = await response.arrayBuffer()
const uint8View = new Uint8Array(arrayBuffer);
const romBuffer = new RomBuffer(uint8View)
currentRomBuffer = romBuffer;
cpu.interface.clearDisplay()
cpu.load(romBuffer)
let timer = 0
async function cycle() {
timer++
if (timer % 5 === 0) {
cpu.tick()
timer = 0
}
await cpu.step();
if (romBuffer !== currentRomBuffer) {
return;
}
timeout = setTimeout(cycle, 3);
}
cycle()
};
const loadRom = async rom => {
const response = await fetch(`./roms/${rom}`)
const arrayBuffer = await response.arrayBuffer()
const uint8View = new Uint8Array(arrayBuffer);
const romBuffer = new RomBuffer(uint8View)
cpu.interface.clearDisplay()
cpu.load(romBuffer)
// if rom is loaded, clear it!
if(this.lastLoad)
clearInterval(this.lastLoad);
let timer = 0
async function cycle() {
timer++
if (timer % 5 === 0) cpu.tick()
await cpu.step()
}
// keep track the handle.
this.lastLoad = setInterval(cycle, 3);
}