web-dev-qa-db-ja.com

javascript:pause setTimeout();

var t = setTimeout("dosomething()", 5000)で設定されたアクティブなタイムアウトが実行されている場合、

とにかく一時停止して再開する方法はありますか?



110
Hailwood

window.setTimeoutを次のようにラップできます。これは、質問で提案したものと似ていると思います。

function Timer(callback, delay) {
    var timerId, start, remaining = delay;

    this.pause = function() {
        window.clearTimeout(timerId);
        remaining -= Date.now() - start;
    };

    this.resume = function() {
        start = Date.now();
        window.clearTimeout(timerId);
        timerId = window.setTimeout(callback, remaining);
    };

    this.resume();
}

var timer = new Timer(function() {
    alert("Done!");
}, 1000);

timer.pause();
// Do some stuff...
timer.resume();
241
Tim Down

このような何かがトリックを行う必要があります。

function Timer(fn, countdown) {
    var ident, complete = false;

    function _time_diff(date1, date2) {
        return date2 ? date2 - date1 : new Date().getTime() - date1;
    }

    function cancel() {
        clearTimeout(ident);
    }

    function pause() {
        clearTimeout(ident);
        total_time_run = _time_diff(start_time);
        complete = total_time_run >= countdown;
    }

    function resume() {
        ident = complete ? -1 : setTimeout(fn, countdown - total_time_run);
    }

    var start_time = new Date().getTime();
    ident = setTimeout(fn, countdown);

    return { cancel: cancel, pause: pause, resume: resume };
}
16
Sean Vieira

いいえ。キャンセルする必要があります(clearTimeout)。開始してからの時間を測定し、新しい時間で再起動します。

9
RoToRa

Tim Downsのわずかに変更されたバージョン answer 。しかし、ティム ロールバック 私の編集なので、私は自分でこれに答えなければなりません。私のソリューションでは、追加のargumentsを3番目(3、4、5 ...)のパラメーターとして使用し、タイマーをクリアすることができます。

function Timer(callback, delay) {
    var args = arguments,
        self = this,
        timer, start;

    this.clear = function () {
        clearTimeout(timer);
    };

    this.pause = function () {
        this.clear();
        delay -= new Date() - start;
    };

    this.resume = function () {
        start = new Date();
        timer = setTimeout(function () {
            callback.apply(self, Array.prototype.slice.call(args, 2, args.length));
        }, delay);
    };

    this.resume();
}

Timが述べたように、IE lt 9では追加のパラメーターは使用できませんが、oldIEでも機能するように少し回避しました。

使用法:new Timer(Function, Number, arg1, arg2, arg3...)

function callback(foo, bar) {
    console.log(foo); // "foo"
    console.log(bar); // "bar"
}

var timer = new Timer(callback, 1000, "foo", "bar");

timer.pause();
document.onclick = timer.resume;
7
yckart

「一時停止」と「再開」は、one-offであるsetTimeoutのコンテキストではあまり意味がありません。 setIntervalですか?その場合、いいえ、一時停止できません。キャンセル(clearInterval)してから、再度スケジュールを設定することしかできません。仕様の タイマーセクション にあるこれらすべての詳細。

// Setting
var t = setInterval(doSomething, 1000);

// Pausing (which is really stopping)
clearInterval(t);
t = 0;

// Resuming (which is really just setting again)
t = setInterval(doSomething, 1000);
6
T.J. Crowder

タイムアウトは簡単に解決策を見つけることができましたが、間隔は少し複雑でした。

この問題を解決するために、次の2つのクラスを思いつきました。

function PauseableTimeout(func, delay){
    this.func = func;

    var _now = new Date().getTime();
    this.triggerTime = _now + delay;

    this.t = window.setTimeout(this.func,delay);

    this.paused_timeLeft = 0;

    this.getTimeLeft = function(){
        var now = new Date();

        return this.triggerTime - now;
    }

    this.pause = function(){
        this.paused_timeLeft = this.getTimeLeft();

        window.clearTimeout(this.t);
        this.t = null;
    }

    this.resume = function(){
        if (this.t == null){
            this.t = window.setTimeout(this.func, this.paused_timeLeft);
        }
    }

    this.clearTimeout = function(){ window.clearTimeout(this.t);}
}

function PauseableInterval(func, delay){
    this.func = func;
    this.delay = delay;

    this.triggerSetAt = new Date().getTime();
    this.triggerTime = this.triggerSetAt + this.delay;

    this.i = window.setInterval(this.func, this.delay);

    this.t_restart = null;

    this.paused_timeLeft = 0;

    this.getTimeLeft = function(){
        var now = new Date();
        return this.delay - ((now - this.triggerSetAt) % this.delay);
    }

    this.pause = function(){
        this.paused_timeLeft = this.getTimeLeft();
        window.clearInterval(this.i);
        this.i = null;
    }

    this.restart = function(sender){
        sender.i = window.setInterval(sender.func, sender.delay);
    }

    this.resume = function(){
        if (this.i == null){
            this.i = window.setTimeout(this.restart, this.paused_timeLeft, this);
        }
    }

    this.clearInterval = function(){ window.clearInterval(this.i);}
}

これらは次のように実装できます。

var pt_hey = new PauseableTimeout(function(){
    alert("hello");
}, 2000);

window.setTimeout(function(){
    pt_hey.pause();
}, 1000);

window.setTimeout("pt_hey.start()", 2000);

この例では、2秒後に「hey」というアラートがスケジュールされる一時停止可能なタイムアウト(pt_hey)を設定します。別のタイムアウトは、1秒後にpt_heyを一時停止します。 3番目のタイムアウトは、2秒後にpt_heyを再開します。 pt_heyは1秒間実行され、1秒間停止してから実行を再開します。 pt_heyは3秒後にトリガーします。

トリッキーな間隔のために

var pi_hey = new PauseableInterval(function(){
    console.log("hello world");
}, 2000);

window.setTimeout("pi_hey.pause()", 5000);

window.setTimeout("pi_hey.resume()", 6000);

この例では、一時停止可能な間隔(pi_hey)を設定して、2秒ごとにコンソールに「hello world」を書き込みます。タイムアウトは、5秒後にpi_heyを一時停止します。 6秒後に別のタイムアウトがpi_heyを再開します。したがって、pi_heyは2回トリガーし、1秒間実行し、1秒間停止し、1秒間実行してから、2秒ごとにトリガーを継続します。

その他の機能

  • clearTimeout()およびclearInterval()

    pt_hey.clearTimeout();およびpi_hey.clearInterval();は、タイムアウトと間隔をクリアする簡単な方法として機能します。

  • getTimeLeft()

    pt_hey.getTimeLeft();およびpi_hey.getTimeLeft();は、次のトリガーの発生がスケジュールされるまでのミリ秒数を返します。

6
TheCrzyMan

/ revive

Class-y構文糖を使用したES6バージョン????

(わずかに変更:start()を追加)

class Timer {
  constructor(callback, delay) {
    this.callback = callback
    this.remainingTime = delay
    this.startTime
    this.timerId
  }

  pause() {
    clearTimeout(this.timerId)
    this.remainingTime -= new Date() - this.startTime
  }

  resume() {
    this.startTime = new Date()
    clearTimeout(this.timerId)
    this.timerId = setTimeout(this.callback, this.remainingTime)
  }

  start() {
    this.timerId = setTimeout(this.callback, this.remainingTime)
  }
}

// supporting code
const pauseButton = document.getElementById('timer-pause')
const resumeButton = document.getElementById('timer-resume')
const startButton = document.getElementById('timer-start')

const timer = new Timer(() => {
  console.log('called');
  document.getElementById('change-me').classList.add('wow')
}, 3000)

pauseButton.addEventListener('click', timer.pause.bind(timer))
resumeButton.addEventListener('click', timer.resume.bind(timer))
startButton.addEventListener('click', timer.start.bind(timer))
<!doctype html>
<html>
<head>
  <title>Traditional HTML Document. ZZz...</title>
  <style type="text/css">
    .wow { color: blue; font-family: Tahoma, sans-serif; font-size: 1em; }
  </style>
</head>
<body>
  <h1>DOM &amp; JavaScript</h1>

  <div id="change-me">I'm going to repaint my life, wait and see.</div>

  <button id="timer-start">Start!</button>
  <button id="timer-pause">Pause!</button>
  <button id="timer-resume">Resume!</button>
</body>
</html>
2
jeremiah.trein

進行状況バーを表示するには、経過時間と残り時間を計算する必要がありました。受け入れられた答えを使うのは簡単ではありませんでした。このタスクでは、「setInterval」は「setTimeout」よりも優れています。したがって、私はこのTimerクラスを作成し、それを任意のプロジェクトで使用できるようにしました。

https://jsfiddle.net/ashraffayad/t0mmv853/

'use strict';


    //Constructor
    var Timer = function(cb, delay) {
      this.cb = cb;
      this.delay = delay;
      this.elapsed = 0;
      this.remaining = this.delay - self.elapsed;
    };

    console.log(Timer);

    Timer.prototype = function() {
      var _start = function(x, y) {
          var self = this;
          if (self.elapsed < self.delay) {
            clearInterval(self.interval);
            self.interval = setInterval(function() {
              self.elapsed += 50;
              self.remaining = self.delay - self.elapsed;
              console.log('elapsed: ' + self.elapsed, 
                          'remaining: ' + self.remaining, 
                          'delay: ' + self.delay);
              if (self.elapsed >= self.delay) {
                clearInterval(self.interval);
                self.cb();
              }
            }, 50);
          }
        },
        _pause = function() {
          var self = this;
          clearInterval(self.interval);
        },
        _restart = function() {
          var self = this;
          self.elapsed = 0;
          console.log(self);
          clearInterval(self.interval);
          self.start();
        };

      //public member definitions
      return {
        start: _start,
        pause: _pause,
        restart: _restart
      };
    }();


    // - - - - - - - - how to use this class

    var restartBtn = document.getElementById('restart');
    var pauseBtn = document.getElementById('pause');
    var startBtn = document.getElementById('start');

    var timer = new Timer(function() {
      console.log('Done!');
    }, 2000);

    restartBtn.addEventListener('click', function(e) {
      timer.restart();
    });
    pauseBtn.addEventListener('click', function(e) {
      timer.pause();
    });
    startBtn.addEventListener('click', function(e) {
      timer.start();
    });
2
Ashraf Fayad

clearTimeout() を調べることができます

または、特定の条件が満たされたときに設定されるグローバル変数に応じて一時停止します。ボタンが押されたように。

  <button onclick="myBool = true" > pauseTimeout </button>

  <script>
  var myBool = false;

  var t = setTimeout(function() {if (!mybool) {dosomething()}}, 5000);
  </script>
1
John Hartsock

イベントで実装することもできます。

時差を計算する代わりに、バックグラウンドで実行し続ける「ティック」イベントのリッスンを開始および停止します。

var Slideshow = {

  _create: function(){                  
    this.timer = window.setInterval(function(){
      $(window).trigger('timer:tick'); }, 8000);
  },

  play: function(){            
    $(window).bind('timer:tick', function(){
      // stuff
    });       
  },

  pause: function(){        
    $(window).unbind('timer:tick');
  }

};
1
meleyal

スライドショーのような機能のためにsetTimeout()を一時停止できるようにする必要がありました。

ここに一時停止可能なタイマーの独自の実装があります。一時停止の改善(カーネルのコメント)やプロトタイピングの形式(Umur Gedikのコメント)など、Tim Downの回答に見られるコメントを統合します。

function Timer( callback, delay ) {

    /** Get access to this object by value **/
    var self = this;



    /********************* PROPERTIES *********************/
    this.delay = delay;
    this.callback = callback;
    this.starttime;// = ;
    this.timerID = null;


    /********************* METHODS *********************/

    /**
     * Pause
     */
    this.pause = function() {
        /** If the timer has already been paused, return **/
        if ( self.timerID == null ) {
            console.log( 'Timer has been paused already.' );
            return;
        }

        /** Pause the timer **/
        window.clearTimeout( self.timerID );
        self.timerID = null;    // this is how we keep track of the timer having beem cleared

        /** Calculate the new delay for when we'll resume **/
        self.delay = self.starttime + self.delay - new Date().getTime();
        console.log( 'Paused the timer. Time left:', self.delay );
    }


    /**
     * Resume
     */
    this.resume = function() {
        self.starttime = new Date().getTime();
        self.timerID = window.setTimeout( self.callback, self.delay );
        console.log( 'Resuming the timer. Time left:', self.delay );
    }


    /********************* CONSTRUCTOR METHOD *********************/

    /**
     * Private constructor
     * Not a language construct.
     * Mind var to keep the function private and () to execute it right away.
     */
    var __construct = function() {
        self.starttime = new Date().getTime();
        self.timerID = window.setTimeout( self.callback, self.delay )
    }();    /* END __construct */

}   /* END Timer */

例:

var timer = new Timer( function(){ console.log( 'hey! this is a timer!' ); }, 10000 );
timer.pause();

コードをテストするには、timer.resume()およびtimer.pause()を数回使用し、残り時間がどれだけあるかを確認します。 (コンソールが開いていることを確認してください。)

SetTimeout()の代わりにこのオブジェクトを使用することは、timerID = setTimeout( mycallback, 1000)timer = new Timer( mycallback, 1000 )に置き換えるのと同じくらい簡単です。 timer.pause()timer.resume()が利用可能になります。

1

とにかくjqueryを使用している場合は、 $。doTimeout プラグインを確認してください。これは、指定した単一の文字列IDでタイムアウトを追跡でき、設定するたびに変更されず、簡単なキャンセル、ポーリングループおよびデバウンスを実装できるなど、setTimeoutよりも大幅に改善されています。もっと。私の最もよく使われるjqueryプラグインの1つ。

残念ながら、すぐに使用できる一時停止/再開はサポートされていません。このためには、おそらく受け入れられた答えと同様に、$。doTimeoutをラップまたは拡張する必要があります。

1
Ben Roberts

clearTimeout より良いものはないと思います。とにかく、いつでも別のタイムアウトをスケジュールして、代わりに「再開」することができます。

0
Nikita Rybak