JavaScript is single-threaded. If some block of code uses execution thread, no other code can be executed. This means your setTimeout()
call must wait until main execution (the one with busy-waiting while
loop) finishes.
Here is what happens: you schedule setTimeout()
to execute after a second and then block main thread for 3 seconds. This means the moment your busy loop finishes, timeout is already 2 seconds too late - and JS engine tries to keep up by calling your timeout as soon as possible - that is, immediately.
In fact this:
while (Date.now() < start + 3000) {}
is one of the worst things to do in JavaScript. You hold JavaScript execution thread for 3 seconds and no other event/callback can be executed. Typically browsers "freeze" in that period of time.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…