Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/74.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何确保递归函数是';在它回来之前我没有再打电话_Javascript_Jquery_Html_Recursion - Fatal编程技术网

Javascript 如何确保递归函数是';在它回来之前我没有再打电话

Javascript 如何确保递归函数是';在它回来之前我没有再打电话,javascript,jquery,html,recursion,Javascript,Jquery,Html,Recursion,我正在用JavaScript和HTML5画布制作一个RPG。对于对话框,我添加了一个“键入”效果,使其看起来好像NPC的对话框是自动键入的(一个字母接一个字母) 当用户按下按钮时,将触发此函数。当函数在string.length中递归并在给定索引处追加每个字符时,我不希望用户能够再次按下按钮,直到函数停止(到达字符串的结束索引) 为此,我添加了$(“#responseButton”).prop('disabled',true)和$(“#responseButton”).prop('disable

我正在用JavaScript和HTML5画布制作一个RPG。对于对话框,我添加了一个“键入”效果,使其看起来好像NPC的对话框是自动键入的(一个字母接一个字母)

当用户按下按钮时,将触发此函数。当函数在string.length中递归并在给定索引处追加每个字符时,我不希望用户能够再次按下按钮,直到函数停止(到达字符串的结束索引)

为此,我添加了
$(“#responseButton”).prop('disabled',true)
$(“#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

我所做的是构建一个快速的
小按钮
抽象,它保存对元素的缓存引用(不要