web-dev-qa-db-fra.com

Javascript - Pause setInterval ()

Comment mettre en pause et reprendre la fonction setInterval () en utilisant Javascript?

Par exemple, j'ai peut-être un chronomètre pour vous dire le nombre de secondes pendant lesquelles vous avez consulté la page Web. Il y a un bouton "Pause" et "Reprendre". La raison pour laquelle clearInterval () ne fonctionnerait pas ici est que si l’utilisateur clique sur le bouton "Pause" à la 40ème seconde et la 800ème milliseconde, lorsqu’il clique sur le bouton "Reprendre", le nombre de secondes écoulées doit augmenter de 1 après 200 millisecondes. Si j'utilise la fonction clearInterval () sur la variable timer (lorsque le bouton de pause est cliqué), puis que j'utilise à nouveau la fonction setInterval () sur la variable timer (lorsque le bouton de reprise est cliqué), le nombre de secondes écoulées augmentera de 1 seulement après 1000 millisecondes, ce qui détruit la précision du chronomètre.

Alors, comment je fais ça?

36
chris97ong

Vous pouvez utiliser un drapeau pour suivre l’état:

var output = $('h1');
var isPaused = false;
var time = 0;
var t = window.setInterval(function() {
  if(!isPaused) {
    time++;
    output.text("Seconds: " + time);
  }
}, 1000);

//with jquery
$('.pause').on('click', function(e) {
  e.preventDefault();
  isPaused = true;
});

$('.play').on('click', function(e) {
  e.preventDefault();
  isPaused = false;
});
h1 {
    font-family: Helvetica, Verdana, sans-serif;
    font-size: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Seconds: 0</h1>
<button class="play">Play</button>
<button class="pause">Pause</button>

C’est ce que je ferais. Je ne sais pas si vous pouvez mettre en pause setInterval.

Remarque: ce système est simple et fonctionne plutôt bien pour les applications qui n'exigent pas un niveau de précision élevé, mais il ne tient pas compte du temps écoulé entre les ticks: si vous cliquez sur Pause après une demi-seconde et plus tard, cliquez sur Play Time sera éteint par une demi-seconde. 

83
Jonas Grumann

Vous ne devriez pas mesurer le temps en fonction d'intervalle. Économisez simplement du temps lorsque la minuterie a démarré et mesurez la différence lorsque la minuterie est arrêtée/en pause. Utilisez setInterval uniquement pour mettre à jour la valeur affichée. Il n’est donc pas nécessaire de suspendre la minuterie et vous obtiendrez ainsi la meilleure précision possible.

7
VitaliyG

Alors que @Jonas Giuro a raison de dire ceci:

Vous ne pouvez pas mettre la fonction setInterval en pause, vous pouvez l’ARRÊTER (clearInterval) ou le laisser fonctionner.

D'autre part, ce comportement peut être simulé avec approche proposée par @VitaliyG :

Vous ne devriez pas mesurer le temps en fonction d'intervalle. Économisez simplement du temps lorsque la minuterie a démarré et mesurez la différence lorsque la minuterie est arrêtée/en pause. Utilisez setInterval uniquement pour mettre à jour la valeur affichée.

var output = $('h1');
var isPaused = false;
var time = new Date();
var offset = 0;
var t = window.setInterval(function() {
  if(!isPaused) {
    var milisec = offset + (new Date()).getTime() - time.getTime();
    output.text(parseInt(milisec / 1000) + "s " + (milisec % 1000));
  }
}, 10);

//with jquery
$('.toggle').on('click', function(e) {
  e.preventDefault();
  isPaused = !isPaused;
  if (isPaused) {
    offset += (new Date()).getTime() - time.getTime();
  } else {
    time = new Date();
  }

});
h1 {
    font-family: Helvetica, Verdana, sans-serif;
    font-size: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Seconds: 0</h1>
<button class="toggle">Toggle</button>

5
sbgoran

Pourquoi ne pas utiliser une approche plus simple? Ajouter une classe!

Ajoutez simplement une classe qui indique à l’intervalle de ne rien faire. Par exemple: en vol stationnaire.

var i = 0;
this.setInterval(function() {
  if(!$('#counter').hasClass('pauseInterval')) { //only run if it hasn't got this class 'pauseInterval'
    console.log('Counting...');
    $('#counter').html(i++); //just for explaining and showing
  } else {
    console.log('Stopped counting');
  }
}, 500);

/* In this example, I'm adding a class on mouseover and remove it again on mouseleave. You can of course do pretty much whatever you like */
$('#counter').hover(function() { //mouse enter
    $(this).addClass('pauseInterval');
  },function() { //mouse leave
    $(this).removeClass('pauseInterval');
  }
);

/* Other example */
$('#pauseInterval').click(function() {
  $('#counter').toggleClass('pauseInterval');
});
body {
  background-color: #eee;
  font-family: Calibri, Arial, sans-serif;
}
#counter {
  width: 50%;
  background: #ddd;
  border: 2px solid #009afd;
  border-radius: 5px;
  padding: 5px;
  text-align: center;
  transition: .3s;
  margin: 0 auto;
}
#counter.pauseInterval {
  border-color: red;  
}
<!-- you'll need jQuery for this. If you really want a Vanilla version, ask -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


<p id="counter">&nbsp;</p>
<button id="pauseInterval">Pause</button></p>

Je recherche cette approche rapide et facile depuis des années. Je publie donc plusieurs versions pour la présenter au plus grand nombre.

4
Aart den Braber

Je sais que ce fil est vieux, mais cela pourrait être une autre solution:

var do_this = null;

function y(){
   // what you wanna do
}

do_this = setInterval(y, 1000);

function y_start(){
    do_this = setInterval(y, 1000);
};
function y_stop(){
    do_this = clearInterval(do_this);
};
0
fallingCode

Le code suivant, fournit un moyen de précision pour suspendre la reprise d'une minuterie.

Comment ça marche:

Lorsque le temporisateur est repris après une pause, il génère un cycle de correction à l'aide d'une seule timeout, qui prend en compte le décalage de pause (heure exacte à laquelle le temporisateur a été mis en pause entre les cycles). Une fois le cycle de correction terminé, il programme les cycles suivants avec une variable setInteval régulière et poursuit normalement l'exécution du cycle.

Cela permet de suspendre/reprendre le chronomètre, sans perdre la synchronisation. 

Code:

function Timer(_fn_callback_ , _timer_freq_){
    let RESUME_CORRECTION_RATE = 2;

    let _timer_statusCode_;
    let _timer_clockRef_;

    let _time_ellapsed_;        // will store the total time ellapsed
    let _time_pause_;           // stores the time when timer is paused
    let _time_lastCycle_;       // stores the time of the last cycle

    let _isCorrectionCycle_;
 
    /**
     * execute in each clock cycle
     */
    const nextCycle = function(){
        // calculate deltaTime
        let _time_delta_        = new Date() - _time_lastCycle_;
        _time_lastCycle_    = new Date();
        _time_ellapsed_   += _time_delta_;

        // if its a correction cicle (caused by a pause,
        // destroy the temporary timeout and generate a definitive interval
        if( _isCorrectionCycle_ ){
            clearTimeout( _timer_clockRef_ );
            clearInterval( _timer_clockRef_ );
            _timer_clockRef_    = setInterval(  nextCycle , _timer_freq_  );
            _isCorrectionCycle_ = false;
        }
        // execute callback
        _fn_callback_.apply( timer, [ timer ] );
    };

    // initialize timer
    _time_ellapsed_     = 0;
    _time_lastCycle_     = new Date();
    _timer_statusCode_   = 1;
    _timer_clockRef_     = setInterval(  nextCycle , _timer_freq_  );


    // timer public API
    const timer = {
        get statusCode(){ return _timer_statusCode_ },
        get timestamp(){
            let abstime;
            if( _timer_statusCode_=== 1 ) abstime = _time_ellapsed_ + ( new Date() - _time_lastCycle_ );
            else if( _timer_statusCode_=== 2 ) abstime = _time_ellapsed_ + ( _time_pause_ - _time_lastCycle_ );
            return abstime || 0;
        },

        pause : function(){
            if( _timer_statusCode_ !== 1 ) return this;
            // stop timers
            clearTimeout( _timer_clockRef_ );
            clearInterval( _timer_clockRef_ );
            // set new status and store current time, it will be used on
            // resume to calculate how much time is left for next cycle
            // to be triggered
            _timer_statusCode_ = 2;
            _time_pause_       = new Date();
            return this;
        },

        resume: function(){
            if( _timer_statusCode_ !== 2 ) return this;
            _timer_statusCode_  = 1;
            _isCorrectionCycle_ = true;
            const delayEllapsedTime = _time_pause_ - _time_lastCycle_;
            _time_lastCycle_    = new Date( new Date() - (_time_pause_ - _time_lastCycle_) );

            _timer_clockRef_ = setTimeout(  nextCycle , _timer_freq_ - delayEllapsedTime - RESUME_CORRECTION_RATE);

            return this;
        } 
    };
    return timer;
};


let myTimer = Timer( x=> console.log(x.timestamp), 1000);
<input type="button" onclick="myTimer.pause()" value="pause">
<input type="button" onclick="myTimer.resume()" value="resume">

Code source:

This Timer est une version simplifiée et modifiée de advanced-timer, une bibliothèque js créée par moi-même, avec beaucoup plus de fonctionnalités.

La bibliothèque complète et la documentation sont disponibles dans NPM et GITHUB

0
colxi