开发西蒙游戏时网页按键后冻结,循环已设终止条件求排查
问题分析与修复方案
核心冻结原因:异步操作与同步循环冲突
你的代码里的while ($c && order_array.length > 0)是同步循环,但内部的setTimeout是异步执行的——也就是说,$c = order_check()要等3秒才会执行,但while循环不会等待,会持续疯狂占用CPU资源,直接导致浏览器冻结。
JavaScript是单线程的,同步循环会阻塞事件队列,异步的setTimeout回调根本没机会执行,$c永远是初始的true,循环永远停不下来。
其他关键问题
- 重复绑定点击事件:
order_check的for循环里,每次都会给.play按钮绑定N次点击事件(N为序列长度),点击一次会触发多个回调,逻辑完全混乱。 - 闭包陷阱:for循环里的
i是全局变量,点击回调执行时i已经等于序列长度,永远拿不到正确的当前索引。 - 逻辑时序错误:
order_check会在用户点击前直接返回结果,根本等不到用户输入,返回值毫无意义。
修复后的代码示例
$(document).ready(function () { var order_array = []; var currentStep = 0; var isUserTurn = false; function press(j) { $("#" + j).addClass("play_pressed"); // 此处可添加音效逻辑 setTimeout(function () { $("#" + j).removeClass("play_pressed"); }, 500); } function order_add() { var jk = Math.floor(Math.random() * 4); var j = 'p'; switch (jk) { case 1: j = 'q'; break; case 2: j = 'r'; break; case 3: j = 's'; break; } order_array.push(j); press(j); } function playSequence() { isUserTurn = false; $("h1").text("Watch the sequence!"); var index = 0; var interval = setInterval(function() { press(order_array[index]); index++; if (index >= order_array.length) { clearInterval(interval); setTimeout(startUserTurn, 1000); } }, 800); } function startUserTurn() { isUserTurn = true; currentStep = 0; $("h1").text("Click the keys in Order!"); } function checkUserInput(e) { if (!isUserTurn) return; var clickedId = e.target.id; if (clickedId === order_array[currentStep]) { press(clickedId); currentStep++; if (currentStep === order_array.length) { // 用户完成当前序列,进入下一轮 isUserTurn = false; setTimeout(function() { order_add(); playSequence(); }, 1000); } } else { // 用户出错,游戏结束 gameOver(); } } function gameOver() { isUserTurn = false; $("h1").text("The game has ended!!"); $("body").addClass("end"); $(".play").off("click", checkUserInput); } // 仅绑定一次点击事件,避免重复绑定 $(".play").click(checkUserInput); $(document).keypress(function (e) { // 防止重复触发游戏 if (order_array.length > 0) return; $("h1").text("The game has begun!!"); order_add(); setTimeout(playSequence, 1000); }); });
关键修复点
- 移除同步while循环,改用异步的"序列播放+用户输入监听"模式,符合JavaScript单线程异步特性。
- 点击事件仅绑定一次,避免重复绑定导致的逻辑混乱。
- 用
currentStep跟踪用户当前需要点击的序列位置,规避闭包陷阱。 - 明确区分"播放序列"和"用户输入"两种状态,防止用户在序列播放时误操作。
内容的提问来源于stack exchange,提问作者Gautam Ranka
相关产品推荐
相关产品推荐

