자바 스크립트 : pause setTimeout ();


119

를 통해 설정된 활성 시간 제한이 실행중인 var t = setTimeout("dosomething()", 5000)경우

일시 중지하고 다시 시작할 수 있습니까?


현재 시간 초과에 남은 시간을 얻을 수있는 방법이 있습니까?
아니면 변수에 시간 제한이 설정되면 현재 시간을 저장하고 일시 중지하고 지금과 다음의 차이를 얻어야합니까?


1
궁금한 사람들을 위해 일시 ​​중지는 예를 들어 : div가 5 초 후에 사라지도록 설정되어 있고, 3 초 (2 초 남음)에 사용자가 div 위에 마우스를 놓으면 시간 초과를 일시 중지합니다. 사용자가 div에서 마우스를 떼면 다시 시작하면 2 초 후에 사라집니다.
Hailwood

답변:


260

다음 window.setTimeout과 같이 포장 할 수 있습니다. 질문에서 제안한 내용과 비슷합니다.

var Timer = function(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();

3
@yckart : 롤백, 죄송합니다. setTimeout()Internet Explorer <= 9에서는 매개 변수를 추가하는 것이 작동하지 않는다는 점을 제외하면 좋은 추가 기능입니다.
Tim Down

4
그렇게 timer.resume(); timer.resume();하면 두 개의 시간 제한이 병렬로 발생합니다. 그렇기 때문에 이력서의 맨 처음부터 단락을 시작 clearTimeout(timerId)하거나 if (timerId) return;단락을 수행 하고 싶을 것 입니다.
커널 '

2
이 대답이 마음에 들었지만 var timerId, start, remaining;클래스 범위 외부에서 remaining = delay;다시 내부를 추가 하여 매개 변수를 잡아야했습니다. 매력처럼 작동합니다!
phillihp

1
@ Josh979 : 당신은 정말로 그렇게 할 필요가 없으며 내부에 있어야하는 변수를 노출하기 때문에 그렇게하는 것은 나쁜 생각입니다. 블록 안에 코드를 붙여 넣었을 수도 있습니다 if (blah) { ... }.
Tim Down

1
어떤 이유로 이것은 초기화 된 후 한 번만 실행됩니다.
peterxz

17

이와 같은 것이 트릭을 수행해야합니다.

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

나는 변화 +new Date()new Date().getTime()보다 빠르고 때문에 : jsperf.com/date-vs-gettime
yckart을

9

아니요. 취소 ( clearTimeout)하고 시작한 이후 시간을 측정 한 다음 새 시간으로 다시 시작해야합니다.


7

Tim Downs 답변 의 약간 수정 된 버전입니다 . 그러나 Tim이 내 편집을 롤백 했기 때문에이 문제에 직접 답해야합니다. 내 솔루션을 사용하면 extra arguments를 세 번째 (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;

6

"일시 중지"와 "이력서"정말의 맥락에서 많은 이해가되지 않는 setTimeoutA는, 일회성 것. 의미 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);

16
setTimeout의 컨텍스트에서 일시 중지 및 다시 시작은 여전히 ​​의미가 있습니다.
dbkaplun

6

Timeout은 해결책을 찾기에 충분히 쉬웠지만 Interval은 약간 까다로 웠습니다.

이 문제를 해결하기 위해 다음 두 가지 클래스를 생각해 냈습니다.

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를 일시 중지합니다. 세 번째 Timeout은 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);

이 예에서는 2 초마다 콘솔에 "hello world"를 작성하도록 일시 중지 가능한 간격 (pi_hey)을 설정합니다. 시간 초과는 5 초 후에 pi_hey를 일시 중지합니다. 또 다른 제한 시간은 6 초 후에 pi_hey를 재개합니다. 따라서 pi_hey는 두 번 트리거되고 1 초 동안 실행되고 1 초 동안 일시 중지되고 1 초 동안 실행 된 다음 2 초마다 트리거를 계속합니다.

기타 기능

  • clearTimeout ()clearInterval ()

    pt_hey.clearTimeout();pi_hey.clearInterval();시간 초과와 간격을 취소 할 수있는 쉬운 방법 역할을합니다.

  • getTimeLeft ()

    pt_hey.getTimeLeft();그리고 pi_hey.getTimeLeft();다음 트리거이 예약 될 때까지하는 시간을 밀리 초 단위로 반환합니다.


우리는 복잡한 필요한 이유 당신이 당신의 생각을 설명 할 수, 클래스 을 일시 중지 setInterval? 나는 단순한 if(!true) return;것이 트릭을 할 것이라고 생각 합니까, 아니면 내가 틀렸습니까?
yckart 2013 년

2
트리거 할 때 호출을 건너 뛰는 대신 문자 그대로 간격을 일시 중지 할 수 있도록 만들었습니다. 게임에서 60 초마다 파워 업이 해제되고 트리거 직전에 게임을 일시 중지하면 방법을 사용하여 다시 전원이 켜질 때까지 기다려야합니다. 그것은 진정으로 멈추는 것이 아니라 단지 전화를 무시하는 것입니다. 대신 My 메서드가 실제로 일시 중지되므로 게임 플레이와 관련하여 파워 업이 '정시'해제됩니다.
TheCrzyMan 2013-08-07

2

진행률 표시 줄을 표시하려면 경과 및 남은 시간을 계산해야했습니다. 받아 들여진 대답을 사용하는 것은 쉽지 않았습니다. 이 작업에서는 '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

/ 부활

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>


1

clearTimeout ()을 살펴볼 수 있습니다.

또는 특정 조건이 충족 될 때 설정되는 전역 변수에 따라 일시 중지됩니다. 버튼을 누르는 것처럼.

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

  <script>
  var myBool = false;

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

1

이벤트로 구현할 수도 있습니다.

시차를 계산하는 대신 백그라운드에서 계속 실행되는 '틱'이벤트 수신을 시작하고 중지합니다.

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

어쨌든 jquery를 사용하고 있다면 $ .doTimeout 플러그인을 확인하십시오 . 이 기능은 setTimeout에 비해 크게 개선되었습니다. 여기에는 지정한 단일 문자열 ID로 시간 제한을 추적하고 설정할 때마다 변경되지 않으며 간편한 취소, 폴링 루프 및 디 바운싱을 구현할 수 있습니다. 더. 가장 많이 사용되는 jquery 플러그인 중 하나입니다.

안타깝게도 즉시 일시 중지 / 다시 시작을 지원하지 않습니다. 이를 위해 $ .doTimeout을 래핑하거나 확장해야합니다. 아마도 허용 된 답변과 유사합니다.


doTimeout이 일시 중지 / 재개를 갖기를 바랐지만 전체 문서, 루핑 예제 및 소스를 볼 때 볼 수 없습니다. 내가 볼 수있는 가장 가까운 일시 중지는 취소이지만 기능이있는 타이머를 다시 만들어야합니다. 내가 뭐 놓친 거 없니?
ericslaw

잘못된 길로 안내해서 죄송합니다. 나는 내 대답에서 그 부정확성을 제거했습니다.
Ben Roberts

1

슬라이드 쇼와 같은 기능을 위해 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()을 사용할 수 있습니다.



0

최고 평점 답변을 기반으로 한 Typescript 구현

/** Represents the `setTimeout` with an ability to perform pause/resume actions */
export class Timer {
    private _start: Date;
    private _remaining: number;
    private _durationTimeoutId?: NodeJS.Timeout;
    private _callback: (...args: any[]) => void;
    private _done = false;
    get done () {
        return this._done;
    }

    constructor(callback: (...args: any[]) => void, ms = 0) {
        this._callback = () => {
            callback();
            this._done = true;
        };
        this._remaining = ms;
        this.resume();
    }

    /** pauses the timer */
    pause(): Timer {
        if (this._durationTimeoutId && !this._done) {
            this._clearTimeoutRef();
            this._remaining -= new Date().getTime() - this._start.getTime();
        }
        return this;
    }

    /** resumes the timer */
    resume(): Timer {
        if (!this._durationTimeoutId && !this._done) {
            this._start = new Date;
            this._durationTimeoutId = setTimeout(this._callback, this._remaining);
        }
        return this;
    }

    /** 
     * clears the timeout and marks it as done. 
     * 
     * After called, the timeout will not resume
     */
    clearTimeout() {
        this._clearTimeoutRef();
        this._done = true;
    }

    private _clearTimeoutRef() {
        if (this._durationTimeoutId) {
            clearTimeout(this._durationTimeoutId);
            this._durationTimeoutId = undefined;
        }
    }

}

0

아래와 같이 서버 측 (Node.js)에서 setTimeout을 일시 중지 할 수 있습니다.

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

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

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

    this.resume();
};

아래와 같이 확인할 수 있습니다.

var timer = new PauseableTimeout(function() {
    console.log("Done!");
}, 3000);
setTimeout(()=>{
    timer.pause();
    console.log("setTimeout paused");
},1000);

setTimeout(()=>{
    console.log("setTimeout time complete");
},3000)

setTimeout(()=>{
    timer.resume();
    console.log("setTimeout resume again");
},5000)

-1

나는 당신이 clearTimeout 보다 더 나은 것을 찾을 것이라고 생각하지 않습니다 . 어쨌든 나중에 '다시 시작'하는 대신 언제든지 다른 시간 제한을 예약 할 수 있습니다.


-1

숨길 div가 여러 개인 경우 an setInterval및 여러 사이클을 사용하여 다음 과 같이 할 수 있습니다 .

<div id="div1">1</div><div id="div2">2</div>
<div id="div3">3</div><div id="div4">4</div>
<script>
    function hideDiv(elm){
        var interval,
            unit = 1000,
            cycle = 5,
            hide = function(){
                interval = setInterval(function(){
                    if(--cycle === 0){
                        elm.style.display = 'none';
                        clearInterval(interval);
                    }
                    elm.setAttribute('data-cycle', cycle);
                    elm.innerHTML += '*';
                }, unit);
            };
        elm.onmouseover = function(){
            clearInterval(interval);
        };
        elm.onmouseout = function(){
            hide();
        };
        hide();
    }
    function hideDivs(ids){
        var id;
        while(id = ids.pop()){
            hideDiv(document.getElementById(id));
        }
    }
    hideDivs(['div1','div2','div3','div4']);
</script>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.