问题
I got a problem with resolution of setTimeout. When I set it to 50 ms, it varies from 51 to even 80 ms. When I use sleep module, I am able to get resolution like 50 µs, so what is the setTimeout function problem to get at least 1 ms? Is there any way to fix/avoid that? The problem with sleep is that it delays everything even when callback function should be shoot, it waits... Is there an alternative solution to shoot some events in delay of exactly 50 ms?
For example with sleep module:
var start = new Date().getTime();
sleep.usleep(50);
console.log(new Date().getTime() - start);`
Result is: 0. And microtime says it is 51 to 57 µs. So what the hell?
回答1:
From the setTimeout docs:
It is important to note that your callback will probably not be called in exactly delay milliseconds
The precision of the delay is determined by how little your code blocks, meaning that if you do a lot of operations on the single thread that your code has, the setTimeout
might be triggered with a lot of delay. On the opposite, it will be almost exact.
You could see the difference for yourself, execute this
var start = Date.now();
setTimeout(function() { console.log(Date.now() - start); }, 500);
for(var i=0; i<999999999; ++i){}
// 1237ms
and notice the difference with this:
var start = Date.now();
setTimeout(function() { console.log(Date.now() - start); }, 500);
// 507ms
回答2:
So, in order to acheive the best possible time rate for something like setTimeout, we want to keep the event loop for a given module as small as possible. This minimizes the amount of time the V8 engine spends doing work for the loop. Best case scenario:
setInterval(function(){}, 50);
If this is the only thing in the file, the precision will be very high, because there is nothing else going on. SO, what we do, is we fork a process for a specific module that does only the work we want to make on this interval. If the only thing within the function is an asynchronous request, it is as good as the above. So we get a very high level of precision on our setInterval function.
In one file we want the following contents, we'll call this file1.js.
var http = require('http');
var options = {
hostname: 'localhost',
port: 8888,
path:'/',
method: 'GET'
}
setInterval(function(){
console.log('File:' + (new Date).getTime() % 50);
//The Modulus of the time in MS should change by no more than 1 MS on consecutive runs, I confirmed this works just dandy on my system(though the first couple intervals were slower in some instances, worse I saw was a 3 MS delay)
var req = http.request(options, function (res) {
res.on('data', function (data) {
console.log(data.toString());
});
});
req.end();
}, 50);
In the second file we can do more work, whatever work we want actually. The important thing is we spawn a process to do the above work, contained within its OWN PROCESS. This allows that processes V8 processor to keep this event loop very small. We still are victim of the operating systems management of the given processes on a CPU, but we can still expect our file1.js module to get attention at least once every millisecond, which since all it does is an async call, followed by looking for the next time it needs to launch said async call, the most delay we get between calls is 1ms(at least that's all I saw on my system). The other file, therefore, can contain any amount of work, and one very important line:
file2.js:
var http = require('http');
var child_process = require('child_process');
http.createServer(function (req, res) {
res.write('Hi There');
res.end();
}).listen(8888);
///Do whatever else you need to do
child_process.fork('file1.js');//Add in this line!!!!
Expected output:
File:29
Hi There
File:29
Hi There
File:30//Notice these values only increase by 0 or 1.
Hi There
File:31
Hi There
File:31
Hi There
File:32
Hi There
File:34//Uh oh, one went up by 2... not terrible
Hi There
File:35
Hi There
File:35
回答3:
Yes, I wish it would be more precise and my funny waitSort could work :)
However it works here but not in node
const posInts = [5,2,7,9,4,6,1,3]
const waitSort = arr => new Promise(done => {
const ret = []
const last = Math.max(...arr)
arr.forEach(i => {
setTimeout(() => {
ret.push(i)
if(i === last){
done(ret)
}
}, i)
})
})
waitSort(posInts).then(console.log)
console.log(posInts)
来源:https://stackoverflow.com/questions/18317717/node-js-settimeout-resolution-is-very-low-and-unstable