Javascript 打字机片段使浏览器无响应

Javascript typewriter snippet makes browser not responding

我有一种方法可以使用 Javascript 为我的文本添加打字机效果。我使用以下代码片段来做到这一点:

const text = document.querySelector('.type')

const content = text.textContent
let counter = 0
text.textContent = ''
while (counter < content.length) {
    setTimeout(function () {
        text.textContent += content[counter];
        counter += 1
    }, 1000)
}

我知道这种方法看起来很荒谬,但我很好奇为什么要这样做。 当我尝试 运行 此代码段时,浏览器 (Chrome) 变得没有响应。 我想知道这段代码是否会产生无限循环,为什么?如果有人可以为我提供一些替代方法来获得想要的结果。

因为setTimeout里面的counter和外面的counter不一样。如果您在一段时间后执行控制台登录计数器,它仍然是 0。

这与作用域有关,这里解释得太多了,但这正是您要找的。简单的解释是,在 function(){} 内部,现在在 setTimeout() 中应用,该函数外部的变量不存在。

因为它不是同一个变量,外面的变量永远不会更新,所以你的循环永远不会停止添加更多超时,所以你的浏览器永远不会停止。


除此之外,在您当前的代码中,所有字符将在 1000 毫秒后同时出现。 setTimeout 不会使 while "wait" 1000ms,它只是告诉 javascript "do this taks, after 1000" 然后继续。你创建一个类似队列的东西,告诉他们在 1000 毫秒后完成该任务。

这两个问题的解决方案(但请仔细阅读范围!),就是利用这些知识为您带来优势:

while (counter < content.length) {
    setTimeout(function () {
        text.textContent += content[counter];
    }, 1000 * counter++)
}

现在我们再次将它们全部放入 'queue',但这次我们告诉每个下一个再等待 1000 毫秒。

setTimeout 不是 'sleep for 1sec then do the code then continue'。

setTimeout 的作用是将其代码添加到 'heap' 并继续 运行 下一行。在超时时间(1000 毫秒)后,执行堆中的代码。

因此,您的函数不断向堆中添加代码,持续 1000 毫秒,直到触发第一次超时(它不会触发,因为您不断添加新的超时 - 进程卡住了),当它应该递增时柜台.

感谢 @Martijn & @Alex Brohshtut 帮助我识别问题并提供有用的解决方案。

我确实使用他们的通知维护我的代码并通过互联网查找,最后我以这种方式做到了:

const text = document.querySelector('.type')

const content = text.textContent
let counter = 0
text.textContent = ''

while (counter < content.length) {
    setTimeout((function (counterCopy) {
        return function () {
            text.textContent += content[counterCopy];
        }
    }(counter)), 1000 * counter++)
}

这是我的第一个代码的问题:

  1. 我在setTimeout的回调函数里面只修改了变量counter的值,它的值没有由于范围原因在循环内发生变化。所以这是一个无限循环,让我的浏览器一晚上都没有响应。

    解决方案:我不得不在回调函数外更改counter的值

  2. 我误解了setTimeout函数,以为它会让脚本停止一段时间然后继续。两位朋友向我展示了它只安排在特定时间后执行其内部的回调函数。所以,我不得不在每次迭代中增加那个时间。

    解决方案:我采纳了@Martijn的建议,用了1000 * counter++的时间。

  3. 当我让 setTimeout 中的函数在 1000 毫秒后执行时,循环继续并增加 counter 的值。所以当函数被执行时,计数器现在的最高值等于 content.length.

    解决方案:我使用了一个函数调用,returns 回调函数本身,但这次使用计数器作为它的参数。这让我有点困惑,但最后效果很好。

    setTimeout((function(counterCopy){
        return function() {
            console.log(counterCopy)
        }
    }(counter)), 1000 * counter++)
    

我在 YouTube 教程中看到的另一种方法 HERE

使用 setInterval 代替 setTimeout:

const text = document.querySelector('.type')

const content = text.textContent
let counter = 0
text.textContent = ''

var typewriter = setInterval(function(){
    text.textContent += content[counter];
    counter++;
    if (counter > (content.length - 1)) {
        clearInterval(typewriter);
    }
}, 1000);