在没有setTimeout的情况下模拟JavaScript中的文本键入效果

Simulating text typing effect in JavaScript without setTimeout

本文关键字:文本 模拟 setTimeout 情况下 JavaScript      更新时间:2023-09-26

我正在制作一个RPG,希望对话框以打字效果显示(在对话框中逐个字母键入)。我遇到了setTimeout()的递归问题,正如我在这里所问的:

如何确保递归函数是';t在返回之前再次调用

一位SO用户建议"避免在setTimeout中使用字符串……多年前就应该停止教授;性能杀手,如果你在用户创建的字符串中进行混搭,会带来安全隐患,很容易犯非严格的eval上下文错误。"

所以,如果我不应该使用setTimeout(),否则我怎么能给屏幕上键入的字符串的每个字符添加延迟呢?

我可以想到的一种方法是将变量计数器设置为x,然后递减(比如说,设置i = 1000,然后循环直到I=0,然后再次重复……直到字符串被完全键入),但这会更快吗?它能解决问题吗?它也没有给我一个很好的感觉,需要多长时间才能减少。在setTimeout()中,可以指定毫秒。

到目前为止,这就是我设计typeEffect的方式(它的类型很好,但我可以不断点击类型按钮来重新运行脚本)。

typeEffect : function (index) {
    $("#responseButton").prop('disabled', true); //wait until typing is done before user can press again
    game.data.enableCycle = false;
    setTimeout(function () {
        $("#npc_dialog").append(game.data.NPCdialog.charAt(index));
        index++;
        if (index < game.data.NPCdialog.length) {
            Utilities.typeEffect(index);
        }
        else {
            game.data.enableCycle = true;
            Utilities.hoverText(); //after type effect, replace appended letters with full dialog, run hoverText to split it into spans (for hover text)
            $("#responseButton").prop('disabled', false);
            $('#npc_dialog').html(game.data.NPCdialog);
        }
    }, 50);     
},

应该使用setTimeout。您不应该在setTimeout中使用字符串

错误:

setTimeout('foo(32)', 1000);

好:

setTimeout(function() {
  foo(32);
}, 1000);

据我所见,你的问题是,每次按下按钮时,你都会启动一个新的并行setTimeout循环,而不会取消之前的循环。这是常见的模式:

var fooTimer = 0;
$(element).click(function(evt) {
  // clear the previous timer, if any
  if (fooTimer) {
    clearInterval(fooTimer);
  }
  // start a new timer
  fooTimer = setInterval(function() {
    foo(32);
  }, 1000);
}

另一件需要注意的事情是:setInterval/setTimeout是唯一的方法。不能使用循环作为延迟,因为这样函数就不会放弃线程。由于JavaScript是单线程的,并且与UI重新绘制共享一个线程,所以您的屏幕永远不会更新。无论运行所有字母的所有循环需要多长时间,沙漏都在旋转,你的浏览器几乎被任何东西屏蔽,最后你会看到所有东西同时出现。也就是说,除非浏览器认为你的代码没有出错,并询问你是否要终止这个糟糕的脚本。

您可以使用setTimeout()或setInterval();这将是做类似事情的首选(唯一?)方式。

我认为另一位SO用户指的是在字符串中设置回调代码的做法,而不是像一段时间以来可能的那样使用函数引用。