Search code examples
javascripthtmlgoogle-chromewhile-loopinfinite-loop

Javascript typewriter snippet makes browser not responding


I had an approach to add a typewriter effect to my text using Javascript. I used the following snippet to do so :

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)
}

I know that this approach seems ridiculous , but I'm curious why it does this. When I try to run this snippet, the browser (Chrome) becomes not responding. I want to know if this code generates an infinite loop, and why? And if someone can provide me some alternative way to get the wanted result.


Solution

  • Thanks to @Martijn & @Alex Brohshtut for helping me recognize the problem and offering helpful solutions.

    I did maintain my code using their notices and by looking up through the internet and finally I did it in that way:

    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++)
    }
    

    And here are the problems with my first code:

    1. I modified the value of the variable counter only inside the callback function of setTimeout, and its value didn't change inside the loop due to scope reasons. So it was an infinite loop which made my browser not responding for a night.

      solution: I had to change the value of counter outside the callback function

    2. I misunderstood the setTimeout function, thought it would make script stop for a time and then continue. The two friends showed me that it only schedules the callback function inside it to be executed after a specific time. So, I had to increase that time in every iteration.

      solution: I took @Martijn's advice and used 1000 * counter++ as a time for it.

    3. When I make the function inside setTimeout get executed after 1000 ms, the loop continues and increases the value of counter. so when the function gets executed, the counter now has its highest value which is equal to content.length.

      solution: I used a function call which returns the callback function itself, but this time with the counter as an argument to it. This looked for me a bit confusing but it worked fine at the end.

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

    Another Approach which I saw in A YouTube Tutorial HERE

    Using setInterval instead of 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);