Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setTimeout does not work with medium-sized negative numbers

If you call setTimeout with a small or large negative number, the callback is run immediately, but with a medium-sized negative number, the callback is never run. Can someone explain this?

// Y and Z are printed, but not X

var x = -7677576503;
var y = -1000000000;
var z = -10000000000;

setTimeout(function () {
  console.log('x');
}, x);
setTimeout(function () {
  console.log('y');
}, y);
setTimeout(function () {
  console.log('z');
}, z);

JSFiddle version

(tested on Chromium 57.0.2987.98 and on Firefox 50.1.0)

like image 266
jcarpenter2 Avatar asked Apr 11 '17 23:04

jcarpenter2


1 Answers

I think I have the answer.
according to MDN:

Browsers including Internet Explorer, Chrome, Safari, and Firefox store the delay as a 32-bit signed integer internally.

the browser is converting this value to a 32-bit signed int. so when it sees the values you've passed we can assume it is actually acting on the ones it converts to that type, and the ECMAScript specification says the return values from bitwise operations must be a 32-bit int.

Runtime Semantics: Evaluation The production A : A @ B, where @ is one of the bitwise operators in the productions above, is evaluated as follows:
... [snipped].
Return the result of applying the bitwise operator @ to lnum and rnum. The result is a signed 32 bit integer.

so if we put that together and test the values you've given:

x | 0 === 912358089, so the timeout will eventually be executed.. just in a while.
y | 0 === -1000000000, and the callback is fired immediately*.
z | 0 === -1410065408, still a negative, still fired immediately*.

*all tests done in chrome latest stable

you can test this with other negatives that would result in a positive when converted to a 32-bit signed int.
-7000000000 | 0 would result in 1589934592, and calling setTimeout(fn, -7000000000) doesn't appear to fire... today.

keeping in mind, this is my best guess at what is happening. good luck!

edit: thanks to Vivek Athalye, I think I have confirmation this is what is happening.

-4294967290000 | 0 === 6000, and if you run setTimeout(_ => console.log(1), -4294967290000) that fires in aprox. 6 seconds.

like image 72
rlemon Avatar answered Sep 24 '22 06:09

rlemon