Aishwar
Aishwar

Reputation: 9724

Is setTimeout with no delay the same as executing the function instantly?

I am looking at some existing code in a web application. I saw this:

window.setTimeout(function () { ... })

Is this the same as just executing the function content right away?

Upvotes: 59

Views: 29762

Answers (4)

steinybot
steinybot

Reputation: 6164

The short answer is no it is not the same.

The description for the delay parameter in the MDN setTimeout documentation is:

The time, in milliseconds that the timer should wait before the specified function or code is executed. If this parameter is omitted, a value of 0 is used, meaning execute "immediately", or more accurately, the next event cycle. Note that in either case, the actual delay may be longer than intended; see Reasons for delays longer than specified below.

Omitting the delay or using a value of 0 will execute in the next event cycle however it may take longer than that. This is the first reason why it is different than executing the function content straight away. For example:

document.getElementById("runNow").addEventListener("click", runNow);
document.getElementById("runNoDelay").addEventListener("click", runNoDelay);

function runNow() {
  clearLog();
  addLog("Start");
  addLog("Hello");
  addLog("End");
}

function runNoDelay() {
  clearLog();
  addLog("Start");
  setTimeout(function() {
    addLog("Hello");
  });
  addLog("End");
}

function clearLog() {
  const log = document.getElementById("log");
  while (log.lastElementChild) {
    log.removeChild(log.lastElementChild);
  }
}

function addLog(message) {
  const newLine = document.createElement("pre");
  newLine.textContent = message;
  document.getElementById("log").appendChild(newLine);
}
<button id="runNow">Run Now</button>
<button id="runNoDelay">Run With No Delay</button>
<div id="log"></div>

Notice how when using setTimeout with no delay the message "End" occurs before "Hello".

Even when the delay is omitted or is 0 there are reasons why it may be longer which may include:

  • "... browsers will enforce a minimum timeout of 4 milliseconds once a nested call to setTimeout has been scheduled 5 times.".
  • The browser tab is inactive.
  • The script has been recognised as a tracking script and is being throttled.
  • Other tasks in the queue took longer than the delay to execute.
  • The browser decides to use some other implementation-defined length of time for whatever reason.

And example of this is:

document.getElementById("run").addEventListener("click", run);

function run() {
  clearLog();
  const now = new Date().getMilliseconds();
  setTimeout(function() {
    timeout(0, now);
  });
}

function clearLog() {
  const log = document.getElementById("log");
  while (log.lastElementChild) {
    log.removeChild(log.lastElementChild);
  }
}

function timeout(nestingLevel, last) {
  const now = new Date().getMilliseconds();
  logline(nestingLevel, now, last);
  if (nestingLevel < 9) {
    setTimeout(function() {
      timeout(nestingLevel + 1, now);
    });
  }
}

function logline(nestingLevel, now, last) {
  const newLine = document.createElement("pre");
  newLine.textContent = `${nestingLevel}                ${now - last}`;
  document.getElementById("log").appendChild(newLine);
}
<button id="run">Run</button>
<pre>nesting level    delay</pre>
<div id="log"></div>

(Adapted from the example on MDN).

Notice how the delay is 0 (or close to 0) until the nesting level reaches a certain point.

It's also important to note that setTimeout is being called with a wrapper function (function () { ... }) which means that the value for this will be the same as if the contents of the function were executed right away.


Chrome (version 92.0.4515.131) and Firefox (version 91.0) enforce a minimum timeout of 4 milliseconds when the nesting level is 4 as shown in the example above.

The HTML Standard says "If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4".

My interpretation is that these browsers are enforcing this minimum timeout 2 tasks too early. It should be applying it to the scheduling of the 7th task where the nesting level is 6 (greater than 5).

At the end of the day the browser can use some other implementation-defined length of time if it wants so it is an interesting but moot point.

Upvotes: 3

Daniel Vandersluis
Daniel Vandersluis

Reputation: 94254

There is a minimum delay that setTimeout uses (4ms as per HTML5, Firefox 3.6 uses 10ms). There is a discussion about it on the Mozilla Developer Center documentation page.

Upvotes: 21

angusC
angusC

Reputation: 1084

It won't necessarily run right away, neither will explicitly setting the delay to 0. The reason is that setTimeout removes the function from the execution queue and it will only be invoked after JavaScript has finished with the current execution queue.

console.log(1);
setTimeout(function() {console.log(2)});
console.log(3);
console.log(4);
console.log(5);
//console logs 1,3,4,5,2

for more details see http://javascriptweblog.wordpress.com/2010/06/28/understanding-javascript-timers/

Upvotes: 105

Gary
Gary

Reputation: 1007

You are missing the millisecond parameter...

setTimeout(function() { /*something*/ }, 0);

The 0 sets the delay to 0 but what it actually does is to let your function "jump the queue" of the browser execution list. The browser has a bunch of things to do such as rendering objects on the page, and by calling this, your function will run as soon as the browser has some cycles.

Upvotes: -2

Related Questions