Javascript 如何确保递归函数是';在它回来之前我没有再打电话
我正在用JavaScript和HTML5画布制作一个RPG。对于对话框,我添加了一个“键入”效果,使其看起来好像NPC的对话框是自动键入的(一个字母接一个字母) 当用户按下按钮时,将触发此函数。当函数在string.length中递归并在给定索引处追加每个字符时,我不希望用户能够再次按下按钮,直到函数停止(到达字符串的结束索引) 为此,我添加了Javascript 如何确保递归函数是';在它回来之前我没有再打电话,javascript,jquery,html,recursion,Javascript,Jquery,Html,Recursion,我正在用JavaScript和HTML5画布制作一个RPG。对于对话框,我添加了一个“键入”效果,使其看起来好像NPC的对话框是自动键入的(一个字母接一个字母) 当用户按下按钮时,将触发此函数。当函数在string.length中递归并在给定索引处追加每个字符时,我不希望用户能够再次按下按钮,直到函数停止(到达字符串的结束索引) 为此,我添加了$(“#responseButton”).prop('disabled',true)和$(“#responseButton”).prop('disable
$(“#responseButton”).prop('disabled',true)函数循环时的code>和$(“#responseButton”).prop('disabled',false)代码>当其索引与dialog string.length匹配时
问题:函数递归时,按钮似乎按预期被禁用,但一旦完成,我可以继续单击已启用的按钮。。。每次按下按钮时,该函数似乎会被多次调用。。。即使之前调用的循环尚未完成。。。这会导致文本不断被覆盖
问题:如何确保函数在再次调用之前重复执行?这就像是有一个滞后时间,如果我一直点击按钮,直到它再次运行
typeEffect : function (index) {
if (index >= game.data.NPCdialog.length) {
game.data.enableCycle = true;
$("#responseButton").prop('disabled', false);
return;
}
else{
$("#responseButton").prop('disabled', true); //wait until typing is done before user can press again
$("#npc_dialog").append(game.data.NPCdialog.charAt(index++));
var t = setTimeout('Utilities.typeEffect('+ (index) +')', 40);
}
},
Javascript是单线程的。除非您有意放弃控制,否则无法调用其他Javascript函数
编辑
诺加德写道:
你肯定看到设定超时了,在那里
我没看到设定超时,就不再叫我雪莉了
我认为他的计划是可行的,只是在启动处理程序之前,有几个事件已经排好了队
Growler,我认为您遇到的问题是,您假设在第一次单击之后,将触发处理程序,并禁用按钮,因此无法生成后续事件。我认为这是不对的
相反,请尝试以下方法:
typeEffect : function() {
var enabled = true;
var process = function(index) {
if (index >= game.data.NPCdialog.length) {
game.data.enableCycle = true;
enabled = true;
$("#responseButton").prop('disabled', false);
}
else {
$("#npc_dialog").append(game.data.NPCdialog.charAt(index));
setTimeout(function() {
process(index+1);
}, 40);
}
};
return function(index) {
if (enabled) {
$("#responseButton").prop('disabled', true);
process(index);
}
};
}(),
Javascript是单线程的。除非您有意放弃控制,否则无法调用其他Javascript函数
编辑
诺加德写道:
你肯定看到设定超时了,在那里
我没看到设定超时,就不再叫我雪莉了
我认为他的计划是可行的,只是在启动处理程序之前,有几个事件已经排好了队
Growler,我认为您遇到的问题是,您假设在第一次单击之后,将触发处理程序,并禁用按钮,因此无法生成后续事件。我认为这是不对的
相反,请尝试以下方法:
typeEffect : function() {
var enabled = true;
var process = function(index) {
if (index >= game.data.NPCdialog.length) {
game.data.enableCycle = true;
enabled = true;
$("#responseButton").prop('disabled', false);
}
else {
$("#npc_dialog").append(game.data.NPCdialog.charAt(index));
setTimeout(function() {
process(index+1);
}, 40);
}
};
return function(index) {
if (enabled) {
$("#responseButton").prop('disabled', true);
process(index);
}
};
}(),
Javascript是单线程的。除非您有意放弃控制,否则无法调用其他Javascript函数
编辑
诺加德写道:
你肯定看到设定超时了,在那里
我没看到设定超时,就不再叫我雪莉了
我认为他的计划是可行的,只是在启动处理程序之前,有几个事件已经排好了队
Growler,我认为您遇到的问题是,您假设在第一次单击之后,将触发处理程序,并禁用按钮,因此无法生成后续事件。我认为这是不对的
相反,请尝试以下方法:
typeEffect : function() {
var enabled = true;
var process = function(index) {
if (index >= game.data.NPCdialog.length) {
game.data.enableCycle = true;
enabled = true;
$("#responseButton").prop('disabled', false);
}
else {
$("#npc_dialog").append(game.data.NPCdialog.charAt(index));
setTimeout(function() {
process(index+1);
}, 40);
}
};
return function(index) {
if (enabled) {
$("#responseButton").prop('disabled', true);
process(index);
}
};
}(),
Javascript是单线程的。除非您有意放弃控制,否则无法调用其他Javascript函数
编辑
诺加德写道:
你肯定看到设定超时了,在那里
我没看到设定超时,就不再叫我雪莉了
我认为他的计划是可行的,只是在启动处理程序之前,有几个事件已经排好了队
Growler,我认为您遇到的问题是,您假设在第一次单击之后,将触发处理程序,并禁用按钮,因此无法生成后续事件。我认为这是不对的
相反,请尝试以下方法:
typeEffect : function() {
var enabled = true;
var process = function(index) {
if (index >= game.data.NPCdialog.length) {
game.data.enableCycle = true;
enabled = true;
$("#responseButton").prop('disabled', false);
}
else {
$("#npc_dialog").append(game.data.NPCdialog.charAt(index));
setTimeout(function() {
process(index+1);
}, 40);
}
};
return function(index) {
if (enabled) {
$("#responseButton").prop('disabled', true);
process(index);
}
};
}(),
问题是setTimeout立即返回,然后代码继续
您需要一个在超时后调用自身并检查按钮是否应启用的函数
下面是一个演示:
问题是setTimeout立即返回,然后代码继续
您需要一个在超时后调用自身并检查按钮是否应启用的函数
下面是一个演示:
问题是setTimeout立即返回,然后代码继续
您需要一个在超时后调用自身并检查按钮是否应启用的函数
下面是一个演示:
问题是setTimeout立即返回,然后代码继续
您需要一个在超时后调用自身并检查按钮是否应启用的函数
下面是一个演示:
如前所述,困扰您的部分是事件反应、异步性和递归函数的组合,它们可能不会在您预期的时间和方式中发挥作用。
它更进一步,但这足以说明哪里出了问题,而不必进入JS裂缝和为其提供动力的浏览器引擎之间的元编程
既然其他答案已经告诉了你为什么它不能按你所想的方式工作,我建议问题的根源在于,你正在试图在可能发生一百次的事情中管理应该只发生一次(切换按钮)的事情,如果你再编写一点代码并将其翻过来,想象起来会容易得多
也许一个看起来像这样的重构会让事情变得更简单:
var button = {
el : $("#responseButton"), // cache your references
setDisabled : function (state) { button.el.prop("disabled", state); },
enable : function () { button.setDisabled(false); },
disable : function () { button.setDisabled(true ); },
handleClick : function () {
button.disable();
Utilities.typeEffect(0, function () { button.enable(); });
}
},
dialogBox = {
// if you're going to call this 100x in a row, cache it
el : $("#npc_dialog"),
append : function (text) { dialogBox.el.append(text); }
},
sec = 1000,
textSpeed = {
fast : 1/25 * sec, // 25x /sec
medium : 1/10 * sec, // 10x /sec
slow : 1/ 5 * sec // 5x /sec
};
button.el.on("click", button.handleClick);
Utilities.typeEffect = function (index, done) {
if (index >= game.data.NPCdialog.length) {
game.data.enableCycle = true;
return done();
} else {
var character = game.data.NPCdialog[index];
dialogBox.append(character);
setTimeout(function () {
Utilities.typeEffect(index+1, done);
}, textSpeed.fast);
}
};
您应该注意到,我在实际的.typeEffect
我所做的是构建一个快速的小按钮
抽象,它保存对元素的缓存引用(不要