It is related to the event loop. Imagine a pile of order, that node.js execute one after another.
setTimeout is (dumbed down version) "put this at the end of the pile, and don't execute it before Xmilliseconds".
So while you are certain it will wait at least that time, you will still need to wait for node.js to get that task back at the top of the pile, which can take a bit of time (in the order of milliseconds).
That's also why it is recommended to use
process.nextTick, which put the task at the top of the pile, instead of
So in your example,
setTimeout(callback, 1) will not be internally transformed to
setTimeout(callback, 4), it's just that there is a 3ms overhead before node.js get back to that task once the timer have elapsed. If there is nothing else in the event loop, and your processor is fast, you may be able to cut down another millisecond, but node.js is just not built to handle time sensitive task at that level. That would put it in the realm of Real Time Programming, which is another use altogether.
To put things in perspective,
setTimeout is, in a crushing majority of use case, used to handle a handful of seconds, so ~1000ms. Is 2~3ms more really that much of a inconvenience?
process.nextTick will also allow node.js to clean the event queue, and prevent
RangeError: Maximum call stack size exceeded exceptions when you chain a lot of asynchronous calls.