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

20,781

Solution 1

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/

Solution 2

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.

Solution 3

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.

Share:
20,781
Aishwar
Author by

Aishwar

Formerly known as "aip.cd.aish"

Updated on July 28, 2022

Comments

  • Aishwar
    Aishwar almost 2 years

    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?

  • Nick Craver
    Nick Craver almost 14 years
    This is the question...the title's asking what happens when there is no delay provided :)
  • Gary
    Gary almost 14 years
    Oh okay. I thought it was a syntax error as various documents state it is a required parameter. Then I tried it out quickly and it worked.
  • Qwerty
    Qwerty about 8 years
    Actually, see other answers for a correct explanation!
  • Matthew Lock
    Matthew Lock over 7 years
    The second parameter is (no longer?) required developer.mozilla.org/en-US/docs/Web/API/…
  • steinybot
    steinybot almost 3 years
    This is only one of the reasons. There are quite a few others.
  • steinybot
    steinybot almost 3 years
    According to the HTML Standard the minimum is only enforced when the nesting level is greater than 5 (or greater than 3 for Chrome and Firefox and possibly others).