45

I am wondering is there a way to tell if a timeout is still set

var t=setTimeout("alertMsg()",3000);

I thought t would be like undefined when you clear it. But it seems to have some id that does not get cleared.

chobo2
  • 83,322
  • 195
  • 530
  • 832
  • See also http://stackoverflow.com/questions/4021374/how-to-know-if-a-timer-is-cleared-or-timed-out-in-javascript – goodeye Jun 24 '13 at 00:57

7 Answers7

52

Not directly, but you can create a wrapper object to give that functionality. A rough implementation is like so:

function Timeout(fn, interval) {
    var id = setTimeout(fn, interval);
    this.cleared = false;
    this.clear = function () {
        this.cleared = true;
        clearTimeout(id);
    };
}

Then you can do something like:

var t = new Timeout(function () {
    alert('this is a test');
}, 5000);
console.log(t.cleared); // false
t.clear();
console.log(t.cleared); // true
Reid
  • 18,959
  • 5
  • 37
  • 37
  • It would be good to see a mention of Gavin's answer below made here. Since setting t to null when you clear it is a much simpler solution that answers the question very nicely. –  Mar 27 '16 at 09:44
  • @NigelPeck: It is simpler, but in virtually every other way a wrapper object is much better from a design perspective: encapsulation, separation of concerns, DRY... – Reid Mar 27 '16 at 14:04
24

First of all, I am giving credit to Reid for portions of this answer, however I felt that I should add some suggestions. With my slight additions to Reid's code, this will:

  • auto-clear when the timeout naturally expires
  • optionally set the scope of the timeout function (rather than just executing in global scope).
  • optionally pass arguments array to the timeout function

here it is:

function Timeout(fn, interval, scope, args) {
    scope = scope || window;
    var self = this;
    var wrap = function(){
        self.clear();
        fn.apply(scope, args || arguments);
    }
    this.id = setTimeout(wrap, interval);
}
Timeout.prototype.id = null
Timeout.prototype.cleared = false;
Timeout.prototype.clear = function () {
    clearTimeout(this.id);
    this.cleared = true;
    this.id = null;
};

[begin comment-free plug] Oh, and I am using the prototype model of adding methods to classes, but only because I prefer it, not because I feel it is more correct [end comment-free plug]

jordancpaul
  • 2,954
  • 1
  • 18
  • 27
  • 1
    This answer is interesting, but misses the point in answering the question, that should be mentioned up-front... Simply set t to null yourself when clearing the timeout and problem solved. –  Mar 27 '16 at 09:46
  • @NigelPeck: I don't see how this answer "misses the point in answering the question". It offers an excellent solution to the original asker's problem. – Reid Mar 27 '16 at 14:05
  • It does, but since the original question can be answered by simply setting the t variable to null, this is a highly verbose answer. There is nothing wrong with that, and it is an excellent solution as you say, but only if such complexity is needed. Since the obvious and simple answer is missed, it misses the point. All I am saying is that a good answer to this question should mention the simple solution first, with this wrapper object solution clearly stated as an alternative. –  Mar 28 '16 at 10:45
  • 1
    Well, to be frank, the question is "Can I determine if a timeout has expired" to which the answer is "No". From that point, _any_ answer is more complex than what is strictly needed for the question. I'm not sure why you're trying to make a distinction between what is too complex for the original poster and what is not... – jordancpaul Apr 11 '16 at 19:22
16

Just set t to 0 in your timeout function:

t = 0;

If you use clearTimeout it sets the timeout id to 0, so checking for t === 0 will check if it's either been cleared or completed.

Gavin
  • 7,544
  • 4
  • 52
  • 72
  • 1
    A much more sensible solution Gavin. Really there is no need for a wrapper object here without suggesting nulling the timeout yourself when you clear it. What could be simpler! –  Mar 27 '16 at 09:44
6

No. In order to know, you'll need to null the t variable after you call clearTimeout. Otherwise there's really no indicator.

And FYI, it's better to pass a direct reference to the function instead of a string that will be eval'd.

var t=setTimeout(alertMsg,3000);
user113716
  • 318,772
  • 63
  • 451
  • 440
0

Like some users suggests in comments, whenever the timeout is either triggered (after the set time has passed) or cleared with clearTimeout, set it manually to false or preferably null. Then you can perform a simple if-check to see if it is active. Also remember to initialize it as false/null if needed.

Created a small test page for this: https://codepen.io/TheJesper/pen/rJzava

Jesper Wilfing
  • 11,157
  • 5
  • 29
  • 32
0

this is only relevant for node.js: setTimeout returns an object, which has the _destroyed property

Welcome to Node.js v18.12.1.
Type ".help" for more information.
> let x = setTimeout(function(){},60000)
undefined
> x
Timeout {
  _idleTimeout: 60000,
  _idlePrev: [TimersList],
  _idleNext: [TimersList],
  _idleStart: 2170,
  _onTimeout: [Function (anonymous)],
  _timerArgs: undefined,
  _repeat: null,
  _destroyed: false,
  [Symbol(refed)]: true,
  [Symbol(kHasPrimitive)]: false,
  [Symbol(asyncId)]: 27,
  [Symbol(triggerId)]: 5
}
> x._destroyed
false
> clearTimeout(x)
undefined
> x._destroyed
true
> 

note: _destroyed is also true if the event has fired

> let y = setTimeout(function(){console.log("yay");},10)
undefined
> yay
> y
Timeout {
  _idleTimeout: 10,
  _idlePrev: null,
  _idleNext: null,
  _idleStart: 198348,
  _onTimeout: [Function (anonymous)],
  _timerArgs: undefined,
  _repeat: null,
  _destroyed: true,
  [Symbol(refed)]: true,
  [Symbol(kHasPrimitive)]: false,
  [Symbol(asyncId)]: 508,
  [Symbol(triggerId)]: 5
}
unsynchronized
  • 4,828
  • 2
  • 31
  • 43
-4

There is another way to check a presence of the timeout. Value which holds a timeout has for default a number value which is increasing with time. So we can do next in "if" construction:

if (someBooleanValue && !parseInt(@changeToCriteriaTimeout) > 0){
  //Do something
}
n3rd
  • 5,989
  • 4
  • 39
  • 56
Oleg
  • 1