What is the difference between setTimeout(fn, 0) and setTimeout(fn, 1)?
I think the answer is "It depends" now.
We can run the code in different platform and browsers:
function setTimeouts() {
setTimeout(function() { console.log(2); }, 2);
setTimeout(function() { console.log(1); }, 1);
setTimeout(function() { console.log(0); }, 0);
}
for (var i = 0; i < 10; i++) {
setTimeouts();
}
NodeJS - setTimeout(fn,0) vs setImmediate(fn)
setTimeout is simply like calling the function after delay has finished. Whenever a function is called it is not executed immediately, but queued so that it is executed after all the executing and currently queued eventhandlers finish first. setTimeout(,0) essentially means execute after all current functions in the present queue get executed. No guarantees can be made about how long it could take.
setImmediate is similar in this regard except that it doesn't use queue of functions. It checks queue of I/O eventhandlers. If all I/O events in the current snapshot are processed, it executes the callback. It queues them immediately after the last I/O handler somewhat like process.nextTick. So it is faster.
Also (setTimeout,0) will be slow because it will check the timer at least once before executing. At times it can be twice as slow. Here is a benchmark.
var Suite = require('benchmark').Suite
var fs = require('fs')
var suite = new Suite
suite.add('deffered.resolve()', function(deferred) {
deferred.resolve()
}, {defer: true})
suite.add('setImmediate()', function(deferred) {
setImmediate(function() {
deferred.resolve()
})
}, {defer: true})
suite.add('setTimeout(,0)', function(deferred) {
setTimeout(function() {
deferred.resolve()
},0)
}, {defer: true})
suite
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').pluck('name'));
})
.run({async: true})
Outputdeffered.resolve() x 993 ops/sec ±0.67% (22 runs sampled)
setImmediate() x 914 ops/sec ±2.48% (57 runs sampled)
setTimeout(,0) x 445 ops/sec ±2.79% (82 runs sampled)
First one gives idea of fastest possible calls. You can check yourself if setTimeout gets called half as many times as other. Also remember setImmediate will adjust to your filesystem calls. So under load it will perform less. I don't think setTimeout can do better.setTimeout is un-intrusive way of calling functions after some time. Its just like its in the browser. It may not be suited for server-side (think why I used benchmark.js not setTimeout).
Why is setTimeout(fn, 0) sometimes useful?
In the question, there existed a race condition between:
- The browser's attempt to initialize the drop-down list, ready to have its selected index updated, and
- Your code to set the selected index
This race existed because JavaScript has a single thread of execution that is shared with page rendering. In effect, running JavaScript blocks the updating of the DOM.
Your workaround was:
setTimeout(callback, 0)
Invoking setTimeout
with a callback, and zero as the second argument will schedule the callback to be run asynchronously, after the shortest possible delay - which will be around 10ms when the tab has focus and the JavaScript thread of execution is not busy.The OP's solution, therefore was to delay by about 10ms, the setting of the selected index. This gave the browser an opportunity to initialize the DOM, fixing the bug.
Every version of Internet Explorer exhibited quirky behaviors and this kind of workaround was necessary at times. Alternatively it might have been a genuine bug in the OP's codebase.
See Philip Roberts talk "What the heck is the event loop?" for more thorough explanation.
How is timing of `setImmediate()` and `setTimeout()` bound by the performance of the process?
The actual trick is in the Timeout constructor which is called by setTimeout
and which increases times below 1 to 1. Thus setTimeout(fn, 0)
is actually equivalent to setTimeout(fn, 1)
.
When libuv initializes, it starts with timers after updating its internal clock, and when one millisecond already passed till then it's gonna pick up the timer before proceeding to the poll phase (which is followed by the setImmediate phase).
Another interesting observation is that multiple timers might also run before and after setImmeadiate:
setTimeout(() => console.log('timer'), 1);
setTimeout(() => console.log('timer'), 1);
setImmediate(() => console.log('immediate'));
// can produce:
// timer
// immediate
// timer
That's because setTimeout
calls getLibuvNow
internally, which will call env->GetNow()
and which not only gets the current time of libuv, but also updates it. Thus it might happen that the timer get put into the timer queue with different due times, and thus the timer phase will only pick up some of them.OK, but what makes so-called "I/O cycles" different from the main module?The main module gets run before libuv is initialized, whereas most other code will run in the poll phase of the libuv loop. Thus the main module initialization is followed by the timer phase, whereas the poll phase is followed by the 'check handles' phase, which among others runs the
setImmediate
callbacks. Thus usually in the main module timers would run before immediates (if they're due) and if scheduled in callbacks, immediates would run before timers.
Related Topics
How to Auto-Slide the Window Out from Behind Keyboard When Textinput Has Focus
Get the Current Year in JavaScript
How to Change the Pop-Up Position of the Jquery Datepicker Control
How to Read JSON File with Fetch() in JavaScript
How to Export Excel Files Using JavaScript
Clear JavaScript Console in Google Chrome
JavaScript Add Method to Object
Loading Local Files with JavaScript Without a Web Server
Initializing Select with Angularjs and Ng-Repeat
Unchecked Runtime.Lasterror While Running Tabs.Executescript
Splicing a JavaScript Array from Within the Callback Passed to Foreach
Can't Set Innerhtml on Tbody in Ie
Angular 2 Karma Test 'Component-Name' Is Not a Known Element
How to Use Promise in Foreach Loop of Array to Populate an Object
Why Is Window (And Unsafewindow) Not the Same from a Userscript as from a <Script> Tag
Explain +Var and -Var Unary Operator in JavaScript