JavaScript 暂停执行函数以等待用户输入
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5551378/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript pausing execution of function to wait for user input
提问by Jort
I'm trying to make a sort of game using the HTML5 canvas, JavaScript and XML. The idea is that you can make a quiz by putting questions and answers in an XML file. I wrote a main loop that loops through all the questions, poses them and checks the correctness of the answer. For now I'm simply using alerts and dialog boxes to answer the questions The problem is that my main loop is one big interconnected whole that walks through the entire game from beginning to end, and instead of having alert boxes posing questions and dialog boxes to answer, immediately after one another, I want some user interaction. The answers to the questions appear on boxes at the bottom of the screen, and the user gets to control a crane to pick the right answer. Here's the snippet of code from the main loop I'm stuck on:
我正在尝试使用 HTML5 画布、JavaScript 和 XML 制作一种游戏。这个想法是您可以通过将问题和答案放在 XML 文件中来进行测验。我写了一个循环所有问题的主循环,提出它们并检查答案的正确性。现在我只是使用警报和对话框来回答问题问题是我的主循环是一个相互关联的大整体,从头到尾贯穿整个游戏,而不是让警报框提出问题和对话框一个接一个地回答,我想要一些用户交互。问题的答案出现在屏幕底部的框中,用户可以控制起重机来选择正确的答案。这是我卡在主循环中的代码片段:
answer = loadQuestion(i);
if (answer == "correct") {
// answered correctly, update scoreArray and load next question
scoreArray[currentQuestion] = "correct";
// show 'next'-button and wait for press to continue
} else {
// answered incorrectly again, update scoreArray and load next question
scoreArray[currentQuestion] = "error";
// show 'next'-button and wait for press to continue
}
As you can see I'm calling loadQuestion, which instantly loads the question, shows the possible answers, and for now immediately throws a dialog box where you can type the answer. This answer is returned and validated.
正如您所看到的,我正在调用 loadQuestion,它会立即加载问题,显示可能的答案,现在立即抛出一个对话框,您可以在其中键入答案。返回并验证此答案。
I have already programmed the controls of the crane, the user can already pick up a box with it. But because I'm calling loadQuestion and expecting it to return a value, this doesn't work. How do I make my main loop "pause" until an answer has been given by the player using the crane, and then proceed? I already tried making the answer a global variable, and just having an empty while answer == ""to keep the function busy doing nothing until answer gets a value, but this just freezes the script. I also messed around with intervals in an attempt to monitor the status of the answer variable, and clear the interval and return the value when this happens, but that simply returns false since the function completes without immediately returning a value.
我已经对起重机的控制进行了编程,用户已经可以用它拿起一个盒子。但是因为我正在调用 loadQuestion 并期望它返回一个值,所以这不起作用。如何让我的主循环“暂停”,直到使用起重机的玩家给出答案,然后继续?我已经尝试将答案设为全局变量,并且只有一个空while answer == ""以保持函数忙于不做任何事情,直到 answer 获得值,但这只会冻结脚本。我还弄乱了间隔,试图监视答案变量的状态,并在发生这种情况时清除间隔并返回值,但这只是返回 false,因为函数完成后没有立即返回值。
回答by T.J. Crowder
How do I make my main loop "pause" until an answer has been given by the player using the crane, and then proceed?
如何让我的主循环“暂停”,直到使用起重机的玩家给出答案,然后继续?
By breaking it up. The only "yield" in JavaScript on browsers is to let your function end and then arrange to get called back later (via setTimeout
, setInterval
, an ajax callback, etc.). In your case, I'd tend to think the trigger to call you back should be the user's action answering the previous question, e.g., a click
handler on the answer boxes or some such (rather than setTimeout
and such, which are automated).
通过打破它。浏览器上 JavaScript 的唯一“收益”是让您的函数结束,然后安排稍后回调(通过setTimeout
、setInterval
、ajax 回调等)。在你的情况下,我倾向于认为给你回电的触发器应该是用户回答上一个问题的动作,例如,click
答案框上的处理程序或其他一些(而不是setTimeout
自动的)。
For instance, this code:
例如,这段代码:
function loopArray(ar) {
var index;
for (index = 0; index < ar.length; ++index) {
doSomething(ar[index]);
}
}
...can be recast like this:
...可以像这样重铸:
function loopArrayAsync(ar, callback) {
var index;
index = 0;
loop();
function loop() {
if (index < ar.length) {
doSomething(ar[index++]);
setTimeout(loop, 0);
}
else {
callback();
}
}
}
The second version yields control back to the browser on every loop iteration. It's also important to note that the second version returns beforethe loops have been completed, whereas the first version waits until all loops are done, which is why the second version has the callback
function it calls when it's done looping.
第二个版本在每次循环迭代时将控制权交还给浏览器。同样重要的是要注意,第二个版本在循环完成之前返回,而第一个版本等待所有循环完成,这就是为什么第二个版本在callback
完成循环时具有它调用的函数。
Code calling the first one might look like this:
调用第一个的代码可能如下所示:
var a = ["one", "two", "three"];
loopArray(a);
// Code that expects the loop to be complete:
doTheNextThing();
doYetAnotherThing();
...whereas using the async version looks like this:
...而使用异步版本如下所示:
var a = ["one", "two", "three"];
loopArrayAsync(a, function() {
// Code that expects the loop to be complete:
doTheNextThing();
doYetAnotherThing();
});
Doing this, you'll probably find you use closures(loop
, above, is a closure), and so this article may be useful: Closures are not complicated
回答by zindel
There is no sync. paused input/output tools in browser JS except of alert
, confirm
and prompt
. Since you don't want to use those - try the following pattern:
没有同步。暂停了浏览器 JS 中的输入/输出工具,除了alert
、confirm
和prompt
。由于您不想使用这些 - 尝试以下模式:
loadQuestion(i, function(answer) {
if (answer == "correct") {
// answered correctly, update scoreArray and load next question
scoreArray[currentQuestion] = "correct";
// show 'next'-button and wait for press to continue
} else {
// answered incorrectly again, update scoreArray and load next question
scoreArray[currentQuestion] = "error";
// show 'next'-button and wait for press to continue
}
resumeGameExecution();
});
I.e. when user answers it - the callback function gets executed and you know that you're good to go.
即当用户回答它时 - 回调函数被执行,你知道你很高兴。
回答by uncaught_exceptions
From what I understand you have a questionnaire application, where you ask a series of questions and then ask the user to drop his answer using some drag and drop control ( a crane).
据我了解,您有一个问卷调查应用程序,您可以在其中提出一系列问题,然后要求用户使用一些拖放控件(起重机)放下他的答案。
I am going to go an a tangent and say the design seems to be wrong. Javascript is event based and having one main thread looping around for user interaction is going to reduce the usability. I will not use any way of stalling the thread ( aka in java). Javascript is not written for such an usecase. Your application will be perceived as non responsive by some browsers and by almost all performance analyzers (like Yslow).
我要去一个切线,说设计似乎是错误的。Javascript 是基于事件的,让一个主线程循环进行用户交互会降低可用性。我不会使用任何方式来拖延线程(也就是在 Java 中)。Javascript 不是为这样的用例编写的。您的应用程序将被某些浏览器和几乎所有性能分析器(如 Yslow)视为无响应。
So I would provide each question with a div identified by a class which internally is a sequence (question1..2). Initially only one question will be enabled or visible. Once user answers the question, I will enable the enabled question. ( on the appropriate event, in this case probably the drop event of drag and drop). Since it is sequential, I will just have to check if the user has answered question1, then I will enable question2 appropriately. The whole flow should be event driven. The event here being the user answering the question.
所以我会为每个问题提供一个由一个类标识的 div,该类在内部是一个序列 (question1..2)。最初只有一个问题会被启用或可见。一旦用户回答了问题,我将启用启用的问题。(在适当的事件上,在这种情况下可能是拖放的放置事件)。由于它是连续的,我只需要检查用户是否回答了问题 1,然后我将适当地启用问题 2。整个流程应该是事件驱动的。这里的事件是用户回答问题。