javascript - 如何使用 setTimeout 延迟代码执行?
问题描述
我仍然是一个 JS 初学者,试图掌握 jQuery 并开始将 Simon Game 编码为一个项目。您有 4 个彩色空间,它们应该以随机顺序点亮并播放声音,从长度为 1 的序列开始。玩家通过单击方块重新创建该序列。如果成功,随机序列长度将增加 1,如果你犯了错误,你必须重新开始。
我正处于简单地创建长度为 5 的随机序列并直观地显示该序列的阶段。这就是我想出的:
var sequence = [];
$("button").click(startGame);
function startGame() {
for (let index = 0; index < 5; index++) {
sequence.push(nextColour());
touchField(index);
// playSound();
}
}
function nextColour() {
var randomNumber = Math.floor(Math.random() * 4) + 1;
if (randomNumber === 1) {
var nextColour = "red";
} else if (randomNumber === 2) {
var nextColour = "blue";
} else if (randomNumber === 3) {
var nextColour = "green";
} else {
var nextColour = "yellow";
}
return nextColour
};
function touchField(index) {
$("." + sequence[index]).addClass("active");
setTimeout(function() {
$("." + sequence[index]).removeClass("active")
}, 300);
}
.active {
border: 1rem solid purple;
}
.red {
border: 1px solid red;
}
.blue {
border: 1px solid blue;
}
.green {
border: 1px solid green;
}
.yellow {
border: 1px solid yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img class="red" src="https://via.placeholder.com/50" alt="">
<img class="blue" src="https://via.placeholder.com/50" alt="">
<img class="green" src="https://via.placeholder.com/50" alt="">
<img class="yellow" src="https://via.placeholder.com/50" alt="">
所以问题是,“.active”类几乎同时从所有方块中添加和删除——这使得无法区分任何类型的序列。所以我想我可以使用“setTimeout();”。但这并不妨碍它这样做。我相信发生的事情是,直到确实执行超时后要评估的表达式,代码才会继续运行,因此几乎同时添加“.active”和超时 5 次 - 这导致它们几乎同时删除。理想情况下,在删除“.active”和将“.active”添加到下一个方块之间有足够的时间。我还尝试将 setTimeout 添加到“touchSquare()”函数调用中。它也不起作用 - 我相信出于同样的原因,它只是继续执行。我希望你能看到我的问题。^^
我看过其他问题,但答案似乎忽略了浏览器在到达 setTimeout 后继续执行代码的事实,例如这里:
如果您将其复制粘贴到控制台中,它根本不会做它应该做的事情,因为在识别 setTimeout 之后代码会继续执行。我希望我能让我的问题对你有意义,这是我第一次在 StackOverflow 上发布问题。如果我能以任何方式改进我提出问题的方式,我非常感谢建设性的批评!
解决方案
要了解它似乎忽略setTimeout()
和 事情似乎同时发生的原因,您需要了解 和 之间的stack
区别event loop
。
放入堆栈的事情会立即(或尽快)发生,这就是for
循环正在做的事情。
放入事件循环的事情发生在给定的最短时间之后(之后,不完全是),这就是setTimeout
正在做的事情。
换句话说,for 循环将 setTimouts 放入事件循环中,彼此间隔毫秒,因此超时会在彼此间隔毫秒内触发。事件循环不像这样做,然后这个,然后那个。它的工作方式类似于“此事件是否达到或超过了它的超时时间?如果是,请尽快执行”
为了达到您正在寻找的效果,您需要一些递归,或者当一个函数调用自身时。这样TouchField()
,在前一个完成之前不会调用下一个,从而按照您期望的方式将事物隔开。
我做了一些非初学者的事情来简化随机序列的生成(使用Array.from()和一个值数组而不是冗长的 if/else 块),并且我添加了第二个超时以便有一点显示字段之间的延迟,(否则同一字段连续两次模糊在一起),但希望这有助于您理解这个概念。
let level = 5, sequence; //increment the level /sequence length as the player progresses
$('button').click(function startGame() {
sequence = Array.from({ length: level },
field => ['red','blue','green','yellow'][Math.floor(Math.random() * 4)]);
TouchField(); //no argument to start recursion / show sequence
});
function TouchField(index = 0) {
if (index <= sequence.length - 1) { //recursion exit condition
// playSound();
$('.' + sequence[index]).addClass('active');
setTimeout(function() {
$('img').removeClass('active');
setTimeout(function() {
TouchField(index + 1); //recursion
}, 500);
}, 500);
}
}
.active {
border: 1rem solid purple !important;
}
.red {
border: 1px solid red;
}
.blue {
border: 1px solid blue;
}
.green {
border: 1px solid green;
}
.yellow {
border: 1px solid yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img class="red" src="https://via.placeholder.com/50" alt="">
<img class="blue" src="https://via.placeholder.com/50" alt="">
<img class="green" src="https://via.placeholder.com/50" alt="">
<img class="yellow" src="https://via.placeholder.com/50" alt="">
<div>
<button>PLAY</button>
</div>
推荐阅读
- tensorflow - 为什么这个 TensorFlow “语言翻译”模型不起作用?
- powerbi - USERNAME() 函数没有返回任何东西
- powershell - 如何在 powershell 中编写语法以重试 Foreach 循环
- python - geany或thonny中的python导入模块不起作用,而它在终端上起作用
- shell - 在 TCL/TK 中找到包含 2 Pattern 的文件
- firebase - 在 watchOS Swiftui 画布上构建时如何解决来自 Firebase 的 Xcode 错误
- html - 引导警报按钮设计已关闭,单击时不会关闭
- swift - 使用 onDisconnectUpdateChildValues 时如何读写 - firebase swift
- sql - 如何解决此访问被拒绝错误?
- python - Python - 如何在 3 列上组合两个数据框并保留两个数据框中的列?