5

If the callback for a setTimeout invocation is added to the job queue (for example, if it is next on the job queue), and a clearTimeout is called on the current tick of the event loop, supplying the id of the original setTimeout invocation. Will the setTimeout callback on the job queue be run?

Or does the runtime magically remove the callback from the job queue?

Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135
Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • I don't believe it runs (ie it's removed from the queue). Trying to find exact clarification in the spec though. – James Thorpe Oct 07 '15 at 14:09
  • I'm actually wondering if it's possible for the code that would determine if a timer is due to be added to the queue can run while other JS is already running - ie it might not actually get put on the queue in the first place. We're talking some pretty low level implementation details here I think. – James Thorpe Oct 07 '15 at 14:14
  • `clearTimeout` would be useless if it did not remove the callback from the queue. – Hacketo Oct 07 '15 at 14:28
  • @Hacketo Indeed - but we're talking here at a level where code is executing _while a timeout happens_ ie you might clear it _after_ it's due to be enqueued. Handily the spec has this covered (see my answer) and checks that it hasn't been cleared before. It seems that the way it works is that timers will _always_ be queued, regardless of whether `clearTimeout` was called, and then aborted when the task is started. – James Thorpe Oct 07 '15 at 14:30
  • @JamesThorpe "ie you might clear it after it's due to be enqueued" , you can only clear a timeout that has already be enqueued. it seem I don't see the point of the question .. Is this [fiddle](http://jsfiddle.net/tc3s0t9p/) an example related to the question ? – Hacketo Oct 07 '15 at 14:46
  • @Hacketo Note we're talking specifically about the queue of events that are due to be run. When a timer's timeout is up, it is added to this queue. We're not talking in general about a queue of things that are due to happen - there's a specific queue in the user agent. Calling `setTimeout(fn, 5000)` doesn't place anything on **this queue** until 5 seconds time, although logically you could say it's "queued to be run". – James Thorpe Oct 07 '15 at 14:53
  • @Hacketo Yes that fiddle is related - I had a simliar one earlier on in this Q, though at the time I was trying to get my head around the permutations of what the Q was asking, I was unsure if it's a good example or not. In hindsight, having now found and read the spec, I think it is a good example - as the timeout _will_ be put on the queue, then cleared from the list of active timers, then the _task will execute_ but see it's been removed from the "list of active timers", so abort the rest of it's execution. – James Thorpe Oct 07 '15 at 14:57
  • 1
    @Hacketo [This may be a better example](http://jsfiddle.net/cbr7m99f/) Both functions are immediately put on the execution queue thanks to [`setTimeout(.., 0)`](http://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful), but the first one runs first and clears the second from running, even though it's already on the queue. – James Thorpe Oct 07 '15 at 15:01

2 Answers2

5

No, it won't run; it will be queued and then subsequently aborted. The specificiation goes through a number of steps when you call setTimeout, one of which (after the minimum timeout, plus and user-agent padded timeouts etc) is eventually:

  1. Queue the task task.

This appears to happen regardless of whether or not the handle that was returned in step 10 has been cleared - ie a call to setTimeout will always result in something being enqueued.

When you call clearTimeout, it:

must clear the entry identified as handle from the list of active timers

ie it doesn't directly affect the process already kicked off in the call to setTimeout. Note however that further up that process, task has been defined as:

  1. Let task be a task that runs the following substeps:

    1. If the entry for handle in the list of active timers has been cleared, then abort this task's substeps.

So when the task begins executing, it will first check if the handle has been cleared.

Community
  • 1
  • 1
James Thorpe
  • 31,411
  • 5
  • 72
  • 93
1

No, it won't be ran.

I don't know which source should be used to back it up officially, but it's at least easy to try for yourself.

function f() {
    var t1 = setTimeout(function() { console.log("YES"); }, 2000);
    sleep(3000);
    clearTimeout(t1);
    console.log("NO");
}
Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135