简体   繁体   中英

How to ensure that two setInterval last the same time

I have a simple progress bar with a JS animation. Every 20ms, the value of the progress bar increases by 0.25. So it takes 20*4*100ms = 8 seconds to complete the progress bar, as you can see on the JSFiddle below.

 function updateProgress(currentValue, expectedValue){ var inProgress = setInterval(function() { currentValue = currentValue + 0.25; $('#progress-bar').attr('value', currentValue); $('#progress-text').text(Math.round(currentValue)); if (currentValue == expectedValue) clearInterval(inProgress); }, 20); } updateProgress(0, 100); 
 <progress id="progress-bar" value="0" max="100"></progress> <div><span id="progress-text">0</span>%</div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> 

So if I take the same code and start the progress bar at 50% instead of 0%, it will take 20*4*50ms = 4 seconds to complete the progress bar, as you can see on the JSFiddle below.

 function updateProgress(currentValue, expectedValue){ var inProgress = setInterval(function() { currentValue = currentValue + 0.25; $('#progress-bar').attr('value', currentValue); $('#progress-text').text(Math.round(currentValue)); if (currentValue == expectedValue) clearInterval(inProgress); }, 20); } updateProgress(50, 100); 
 <progress id="progress-bar" value="50" max="100"></progress> <div><span id="progress-text">50</span>%</div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> 

I would like the function to always have the same time to execute, lookless of the starting value. For example 0 to -> 100 : 4 seconds, and 50 to -> 100 also 4 seconds.

I tried this but it does not work :

function updateProgress(currentValue, expectedValue){
  var interval = 4000 / (expectedValue - currentValue) / 4;

  var inProgress = setInterval(function() {
      currentValue = currentValue + 0.25;
      $('#progress-bar').attr('value', currentValue);
      $('#progress-text').text(Math.round(currentValue));
      if (currentValue == expectedValue) clearInterval(inProgress);
  }, interval);
}

updateProgress(50, 100);

I think I'd use requestAnimationFrame for this, this is pretty much what it's designed for.

 function updateProgress(currentValue, expectedValue){ var valueDelta = expectedValue - currentValue, startTime = performance.now(); nextFrame(startTime); function nextFrame(time) { var value = Math.min(expectedValue, currentValue + valueDelta * (time - startTime) / 4000); setValue(value); if (value !== expectedValue) { requestAnimationFrame(nextFrame); } } function setValue(value) { $('#progress-bar').attr('value', value); $('#progress-text').text(Math.round(value)); } } updateProgress(50, 100); 
 <progress id="progress-bar" value="50" max="100"></progress> <div><span id="progress-text">50</span>%</div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> 

Whether you choose to use requestAnimationFrame or setInterval , I think the key thing is to base your animation on the current time rather than assuming that the timer will be called on schedule.

When I run your original code it works fine for me. My guess would be that the problem is the timer not being called on schedule when the interval is very small, that will be platform dependent. setInterval is not super accurate at the best of times but for the full range, 0 to 100, you'll be relying on a 10ms timer, which is small enough to be problematic.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM