Why setInterval accepts only 2^31-1 delay values? - javascript

According to the specification,
long setInterval(Function handler, optional long timeout, any... arguments);
setInterval() is supposed to accept long timeout delay.
However, on 64bit Linux it behaves like it was a signed 32bit int.
I didn't test on other platforms, please try and leave a comment.
The obvious question is - Why?
Can someone explain why do I get instantly output of this:
let maxSigned32 = 2147483647;
let safeInt = maxSigned32 + 1;
console.log(safeInt);
console.log(Number.MAX_SAFE_INTEGER);
console.log(safeInt < Number.MAX_SAFE_INTEGER); // true
let days = Math.round(safeInt / (1000.0 * 60 * 60 * 24));
console.log(safeInt + ' ms is ~' + days + ' days');
setTimeout(() => {
console.log('I should not see this today')
}, safeInt);
I get this (incorrect?) results both on Chrome 52 and Firefox 48.
Interestingly, when I built and tried with latest ChakraCore, it behaves more reasonable.

The long type in Web IDL shouldn't be compared to its C/C++ namesake.
Its definition can be found here:
The long type is a signed integer type that has values in the range [−2147483648, 2147483647].

Related

Javascript: Create Function that executes a callback function at random intervals on average of 1~2 times per minute

I have this problem that came up and I realized that I don't understand callbacks nearly as good as I should.
The way it's worded makes me think that I need to make it a set interval, but then you see that there is the syntax of "function randomExecution(callback) {}" and that really trips me up.
On top of all of this, this problem really makes me realize how inefficient I am at breaking down a problem into smaller parts. I see the "make sure it's on average about 1~2 times per minute" and I just get lost.
(I get that i can be less than 10 seconds that I have the min set to, but I'm pretty lost here and that was my only solution to make it so it doesn't get called within ten seconds)
What am I doing wrong here?
Also, any advice on how to approach questions like this would be greatly appreciated.
Cheers!
The Problem:
function randomExecution(callback) {
// start an interval that executes `callback()` at random intervals
// make sure it's on average about 1~2 times per minute
// make sure it doesn't execute twice within 10 seconds
}
My attempt:
function randomExecution(callback) {
const min = 10
const max = 120
const random = Math.floor(Math.random() * (max - min + 1) + min)
// callback = console.log('Wait for ' + random + ' seconds')
return random
}
setInterval(console.log(`hi, after ${randomExecution()} seconds`) , randomExecution)
The problem lies in the fact that you use the function SetInterval, which, as the name suggests, is used to call a specified function repeatedly after a fixed interval. A better approach would be to create a recursive loop with SetTimeout, where your code would look like this:
function example() {
console.log('See you soon!')
}
function randomExecution(callback) {
// start an interval that executes `callback()` at random intervals
// make sure it's on average about 1~2 times per minute
// make sure it doesn't execute twice within 10 seconds
const min = 30
const max = 60
var random = Math.floor(Math.random() * (max - min + 1) + min)
setTimeout(function() {
callback();
randomExecution(callback);
}, random * 1000);
}
randomExecution(example)

Date object in Firefox always returns milliseconds rounded to hundreds

I found this behavior by accident when I recently used console.time. In Firefox it always returns either 0ms or 100ms. This happens because the date is always rounded to hundreds of milliseconds. For example +new Date() will return 1552469978800 instead of 1552469978877. Do you know since when is this a thing or how can I possibly get exact time? Also affects setTimeout and setInterval.
This happens because the date is always rounded to hundreds of milliseconds.
I don't see that behavior in Firefox v65 on *nix, nor v48, v56, v57, or v65 on Windows.
But if it's happening in some versions or on some platforms, it may have been a response to Spectre. For the same reason, the alternative I would have pointed out to (performance.now) is less useful than it would otherwise be, because:
The timestamp is not actually high-resolution. To mitigate security threats such as Spectre, browsers currently round the results to varying degrees. (Firefox started rounding to 1 millisecond in Firefox 60.) Some browsers may also slightly randomize the timestamp. The precision may improve again in future releases; browser developers are still investigating these timing attacks and how best to mitigate them.
Finally found a final answer to this problem. The whole problem is privacy.resistFingerprinting setting enabled by default in recent versions of Firefox.
Fingerprinting protection probably makes more problems than good in this case. You are now completely unable to properly set timezone in Javascript so some web app, for example Slack will always show GMT+0 time instead of your actual time.
Also another annoying thing is that JavaScript animations (especially affecting jQuery plugins) which use setInterval or setTimeout functions are now running at 10 frames per second.
When you disable fingerprinting protection, everything works fine after you restart the browser.
Try this:
function convert( ms ) {
var seconds = ms / 1000;
var hours = parseInt( seconds / 3600 );
seconds = seconds % 3600;
var minutes = parseInt( seconds / 60 );
seconds = seconds % 60;
var pad = function(x) { return (x < 10) ? "0"+x : x; }
return pad(hours)+":"+
pad(minutes)+":"+
pad(seconds);
}
var time = 100000000;
console.log(convert(time));
That would convert milliseconds to hours : minutes : seconds format.

How to disable skipping in JavaScript console.log() [duplicate]

This question already has answers here:
How do I disable firefox console from grouping duplicate output?
(5 answers)
Closed 5 years ago.
I'm trying to measure time taken by a function to execute in JS.
When I try to console.log() the elapsed time, some blue numbers appear in the console and some of the logs are gone.
When I counted the appeared number, it matched with the number of lines of skipped log.
I'm sure you can notice the problem at the right part of screenshot.
I would like the console to show all of the logs.
Is there anything I can do? BTW, the browser is Firefox 58.0b8. (Developer Edition)
Not sure, if this will serve your purpose but this is a workaround not a solution provided by any browser.
You can add a wrapper function for console.log like below
function logToConsole(number) {
var randomNumber = Math.floor(Math.random() * 6) + 1;
console.log(number.toString() + Array(randomNumber).join(" "));
}
Here, each time console.log is called, it is padded with a random number between 1 and 6. (You can also increase the range, if you feel that there is a chance for error)
Complete example below.
function logToConsole(number) {
var randomNumber = Math.floor(Math.random() * 6) + 1;
console.log(number.toString() + Array(randomNumber).join(" "));
}
logToConsole(0.1111);
logToConsole(0.1111);
logToConsole(0.1111);
logToConsole(0.1111);
logToConsole(0.1111);
Rather than do console.log, why don't you write the time to an array a print that at the end of the test?
There are benchmarking methods in console that have very high accuracy. You can use console.time(key) and console.timeEnd(key).
https://developer.mozilla.org/en-US/docs/Web/API/Console/time
// kick off
console.time('asdf')
// later
console.timeEnd('asdf')
// VM18707:1 asdf: 2077.59716796875ms
Even calling timeEnd immediately will yield different results, so it's not likely to have multiple consecutive equal results with a more complex script.

Javascript Date/Time Parsing, UTC to Local Time Broke

I have a strange timezone/date formatting issue that recently came up with some new code, and what makes it more strange is that it only affects two months - August and September.
The code takes a date string with UTC time formatted like this:
10-06-2017 09:29:15
And converts it to a new string with the same format but with local time. The zeroPad function ensures that the format remains the same.
We implemented it in March and everything worked fine. It's within Classic ASP on IIS9/Server 2012.
As soon as we got to August, it broke. 08-10-2017 09:33:06 becomes 12-09-2016 20:33:06.
Can anyone see what I've done wrong?
function jsConvert(dateString) {
var patterns = dateString.split(/[\-\s:]/g);
var date = new Date(parseInt(patterns[2]),
parseInt(patterns[0]) - 1,
parseInt(patterns[1]),
parseInt(patterns[3]),
parseInt(patterns[4]),
parseInt(patterns[5]));
date.setTime(date.getTime() - getTimezoneOffset() * 60 * 1000);
var result = zeroPad(date.getMonth() + 1);
result += '-' + zeroPad(date.getDate());
result += '-' + date.getFullYear();
result += ' ' + zeroPad(date.getHours());
result += ':' + zeroPad(date.getMinutes());
result += ':' + zeroPad(date.getSeconds());
return result;
}
function zeroPad(number) {
return (number < 10) ? '0' + number : number;
}
What are the units of time in your getTimezoneOffset() function?
Your code is written as though the getTimezoneOffset() function returns a number of minutes, since you are multiplying by 60 and then 1000, to get millseconds.
But if your getTimezoneOffset is returning seconds, you will be over-doing the multiplication and therefore jumping back too far in time.
I think it would have to be milliseconds, to jump back the distance you are getting. #CBroe above mentions that perhaps you mean the builtin getTimezoneOffset function, which is indeed in minutes. Perhaps you have a separate getTimezoneOffset function defined in your code elsewhere, that returns an answer in milliseconds? In which case CBroe's answer fixes it.
My next suggestion would be to add lines of debugging code
For example, could you add the following?
At the beginning, add console.log("A",dateString).
After var patterns = dateString.split(/[\-\s:]/g); add a line console.log("B",patterns);.
After var date = ...(patterns[5])); add a line console.log("C",date);.
After date.setTime...1000); add a line console.log("D",date); console.log("E",getTimezoneOffset());.
If you show us the output of these lines, we should be able to pinpoint the problem easily. I have included item E because I am just wondering if there is yet another getTimezoneOffset() function in your system, which we are not aware of, or something. Seeing its value will help reassure everyone.
Meanwhile can you confirm the time zone you are running the code in? I am guessing it is in the USA rather than Europe, from your preference for putting month before the day?
So as it turns out this is a known, albeit obscure issue. It has to do with the fact that parseInt assumes that numbers with leading zeros are NOT base 10, but instead radix. It's well documented here: Javascript parseInt() with leading zeros
Once I made the change to:
parseInt(patterns[2]**, 10**);
All was good.
Thanks for the input.

How to get a microtime in Node.js?

How can I get the most accurate time stamp in Node.js?
ps My version of Node.js is 0.8.X and the node-microtime extension doesn't work for me (crash on install)
In Node.js, "high resolution time" is made available via process.hrtime. It returns a array with first element the time in seconds, and second element the remaining nanoseconds.
To get current time in microseconds, do the following:
var hrTime = process.hrtime()
console.log(hrTime[0] * 1000000 + hrTime[1] / 1000)
(Thanks to itaifrenkel for pointing out an error in the conversion above.)
In modern browsers, time with microsecond precision is available as performance.now. See https://developer.mozilla.org/en-US/docs/Web/API/Performance/now for documentation.
I've made an implementation of this function for Node.js, based on process.hrtime, which is relatively difficult to use if your solely want to compute time differential between two points in a program. See http://npmjs.org/package/performance-now . Per the spec, this function reports time in milliseconds, but it's a float with sub-millisecond precision.
In Version 2.0 of this module, the reported milliseconds are relative to when the node process was started (Date.now() - (process.uptime() * 1000)). You need to add that to the result if you want a timestamp similar to Date.now(). Also note that you should bever recompute Date.now() - (process.uptime() * 1000). Both Date.now and process.uptime are highly unreliable for precise measurements.
To get current time in microseconds, you can use something like this.
var loadTimeInMS = Date.now()
var performanceNow = require("performance-now")
console.log((loadTimeInMS + performanceNow()) * 1000)
See also: Does JavaScript provide a high resolution timer?
node v10 and later: you should be using process.hrtime.bigint(), which yields a single BigInt number rather than an array. process.hrtime() has been marked "legacy"
Older than node v10: As stated by vaughan, process.hrtime() is available within Node.js - its resolution are nanoseconds and therefore its much higher. This function returns an array [seconds, nanoseconds] containing the current real-time high-resolution value, but note that it is not tied to any specific clock, meaning the difference in two successive values tells you how much time passed, but individual values tell you nothing meaningful.
Other JS environments: new Date().getTime()? This gives you a timestamp in milliseconds.
Update:
now('milli'); // 120335360.999686
now('micro') ; // 120335360966.583
now('nano') ; // 120335360904333
Known that now is :
const now = (unit) => {
const hrTime = process.hrtime();
switch (unit) {
case 'milli':
return hrTime[0] * 1000 + hrTime[1] / 1000000;
case 'micro':
return hrTime[0] * 1000000 + hrTime[1] / 1000;
case 'nano':
default:
return hrTime[0] * 1000000000 + hrTime[1];
}
};
The BigInt data type is supported since Node.js 10.7.0. (see also the blog post announcement). For these supported versions of Node.js, the process.hrtime([time]) method is now regarded as 'legacy', replaced by the process.hrtime.bigint() method.
The bigint version of the process.hrtime() method returning the current high-resolution real time in a bigint.
const start = process.hrtime.bigint();
// 191051479007711n
setTimeout(() => {
const end = process.hrtime.bigint();
// 191052633396993n
console.log(`Benchmark took ${end - start} nanoseconds`);
// Benchmark took 1154389282 nanoseconds
}, 1000);
tl;dr
Node.js 10.7.0+ - Use process.hrtime.bigint()
Otherwise - Use process.hrtime()
There's also https://github.com/wadey/node-microtime:
> var microtime = require('microtime')
> microtime.now()
1297448895297028
You can also use performance API that works both in NodeJS and Browser:
var start = performance.timing ?
performance.timing.navigationStart :
performance.timeOrigin;
var time = (performance.now() + start) * 1000;
The Performance API stores value in floating-point number and the fraction is microseconds.
Node.js nanotimer
I wrote a wrapper library/object for node.js on top of the process.hrtime function call. It has useful functions, like timing synchronous and asynchronous tasks, specified in seconds, milliseconds, micro, or even nano, and follows the syntax of the built in javascript timer so as to be familiar.
Timer objects are also discrete, so you can have as many as you'd like, each with their own setTimeout or setInterval process running.
It's called nanotimer. Check it out!
To work with more precision than Date.now(), but with milliseconds in float precision:
function getTimeMSFloat() {
var hrtime = process.hrtime();
return ( hrtime[0] * 1000000 + hrtime[1] / 1000 ) / 1000;
}
The only way nowdays is call some 3rd party.
A lib with compiled function written on C (does't matter language, the point is OS syscall). Write your own or use for example https://www.npmjs.com/package/microtime (src https://github.com/wadey/node-microtime/blob/master/src/microtime.cc)
Spawn a process with date +%s%N, works on Linux out of box. Possible by using require('child_process').exec. I have no idea how accurate time would be because of performance of this solution
Note: process.hrtime is not about current time,
These times are relative to an arbitrary time in the past, and not related to the time of day.
[https://www.geeksforgeeks.org/node-js-process-hrtime-method/]
Edit:
Use jcubic's or Alexandr's answers below :
https://stackoverflow.com/a/69870775/2550964 https://stackoverflow.com/a/72741299/2550964
I'm not so proud about this solution but you can have timestamp in microsecond or nanosecond in this way:
const microsecond = () => Number(Date.now() + String(process.hrtime()[1]).slice(3,6))
const nanosecond = () => Number(Date.now() + String(process.hrtime()[1]).slice(3))
// usage
microsecond() // return 1586878008997591
nanosecond() // return 1586878009000645600
// Benchmark with 100 000 iterations
// Date.now: 7.758ms
// microsecond: 33.382ms
// nanosecond: 31.252ms
Know that:
This solution works exclusively with node.js,
This is about 3 to 10 times slower than Date.now()
Weirdly, it seems very accurate, hrTime seems to follow exactly js timestamp ticks.
You can replace Date.now() by Number(new Date()) to get timestamp in milliseconds
Edit:
Here a solution to have microsecond with comma, however, the number version will be rounded natively by javascript. So if you want the same format every time, you should use the String version of it.
const microsecondWithCommaString = () => (Date.now() + '.' + String(process.hrtime()[1]).slice(3,7))
const microsecondWithComma = () => Number(Date.now() + '.' + String(process.hrtime()[1]).slice(3,7))
microsecondWithCommaString() // return "1586883629984.8997"
microsecondWithComma() // return 1586883629985.966
A rewrite to help quick understanding:
const hrtime = process.hrtime(); // [0] is seconds, [1] is nanoseconds
let nanoSeconds = (hrtime[0] * 1e9) + hrtime[1]; // 1 second is 1e9 nano seconds
console.log('nanoSeconds: ' + nanoSeconds);
//nanoSeconds: 97760957504895
let microSeconds = parseInt(((hrtime[0] * 1e6) + (hrtime[1]) * 1e-3));
console.log('microSeconds: ' + microSeconds);
//microSeconds: 97760957504
let milliSeconds = parseInt(((hrtime[0] * 1e3) + (hrtime[1]) * 1e-6));
console.log('milliSeconds: ' + milliSeconds);
//milliSeconds: 97760957
Source: https://nodejs.org/api/process.html#process_process_hrtime_time
Get hrtime as single number in one line:
const begin = process.hrtime();
// ... Do the thing you want to measure
const nanoSeconds = process.hrtime(begin).reduce((sec, nano) => sec * 1e9 + nano)
Array.reduce, when given a single argument, will use the array's first element as the initial accumulator value. One could use 0 as the initial value and this would work as well, but why do the extra * 0.
there are npm packages that bind to the system gettimeofday() function,
which returns a microsecond precision timestamp on Linux. Search for
npm gettimeofday. Calling C is faster than process.hrtime()
process.hrtime() not give current ts.
This should work.
const loadNs = process.hrtime(),
loadMs = new Date().getTime(),
diffNs = process.hrtime(loadNs),
microSeconds = (loadMs * 1e6) + (diffNs[0] * 1e9) + diffNs[1]
console.log(microSeconds / 1e3)
better?
Number(process.hrtime().join(''))

Categories