user12102598
user12102598

Reputation:

How am I able to add timing to javascript that alters text every second?

I would like this code to count up from 0 to 940 (very fast) and alter the text every time it updates

Here's my code (inside my head tag):

    <script type="text/javascript">
      function sleep(milliseconds) {
        const date = Date.now();
        let currentDate = null;
        do {
          currentDate = Date.now();
        } while (currentDate - date < milliseconds);
      }
      function onLoad(){
        var x = document.getElementById("numberID");
        var n = 940;
        var text = "";
        for(i = 0;i < n + 1;i++){
          text = i;
          x.innerHTML = text;
          sleep(1);
        }
      }
    </script>

At the moment, it just waits a second then displays '940' on screen and doesn't display it counting up.

Any help would be appreciated, thanks!

Here's the code I recently put in, still doesn't work:

const x = document.getElementById("numberID");
      function newFrame(duration, start =  performance.now()) {
        requestAnimationFrame((now) => {
          const elapsed = now - start;
          x.innerText = Math.max(0, Math.min(duration, 
          Math.round(elapsed)));
          if(elapsed < duration)
              newFrame(duration, start);
          })
        }
      }
      newFrame(940);

Upvotes: 1

Views: 148

Answers (2)

Sheraff
Sheraff

Reputation: 6692

Using a while loop to "sleep" is going to block the page's thread and nothing else can happen in the meantime. This is considered bad practice.

setTimeout guarantees that at least the defined time has passed, but can take (much) longer. This is imprecise, and especially bad for shorter intervals. Same with setInterval. They're also not recommended for callbacks that involve updating the DOM.

What you need to do is use a requestAnimationFrame.

function newFrame(duration, start =  performance.now()) {
  requestAnimationFrame((now) => {
    const elapsed = now - start
    console.log(`time passed: ${elapsed} ms`)
    if(elapsed < duration)
        newFrame(duration, start)
  })
}
newFrame(940)

In your specific case, I'd replace the console.log statement put there for didactic purposes, with something along the lines of:

x.innerText = Math.max(0, Math.min(duration, Math.round(elapsed)))

Here's what that would look like:

const x = document.getElementById("numberID")

function newFrame(duration, start =  performance.now()) {
  requestAnimationFrame((now) => {
    const elapsed = now - start
    x.innerText = Math.max(0, Math.min(duration, Math.round(elapsed)))
    if(elapsed < duration)
        newFrame(duration, start)
  })
}

newFrame(940)
<span id="numberID"></span>

Upvotes: 5

gugateider
gugateider

Reputation: 2039

The sleep function is not doing anything, what you need is a setTimeout to display the text at every x milliseconds.

Something like the below will work.

let x = null;
let timeout = null;
const changeText = (text) => {
  x.innerHTML = text;
  clearTimeout(timeout);
}

function onLoad() { 
 x = document.getElementById("numberID");
 const n = 940;
 const t = .01; // in seconds
 for( let i = 0; i <= n; i++) { 
  timeout = setTimeout( () => changeText((i+1).toString()), (t * i) * 1000);  
 }
 
}

onLoad();
<span id="numberID"></span>

Upvotes: 0

Related Questions