With Javascript, in an application that uses an update function that runs for every rendered frame and seeks every minutest optimization:
If one wants to run code every so often and the precision of time is mostly unimportant, is there a wise choice between using a setTimeout loop or just building a timer into the update function of the application?
For instance, does setTimeout have some unexpected computational cost that makes it clearly slower? Or, on the other hand, would setTimeout positively affect the application because Javascript is not in a hurry to make a setTimeout callback happen?
Using a timestamp differential is better than a setTimeout, but still you need to have the render loop. Therefore you can use the timestamp differential that requestAnimationFrame sends as parameter to the callback function.
I hope this answers your question.
Also keep in mind that (as you mentioned), setTimeout is postponed to the end of the stack-call. That's why in node.js you have other means of "deferring" functions, and also you have a faster way to compute timestamp differential by using process.hrtime instead of having to use Date object.
Long answer short would be:
Use the parameter sent by requestAnimationFrame to the callback.
Related
In a browser, I am trying to make a well-behaved background job like this:
function run() {
var system = new System();
setInterval(function() { system.step(); }, 0);
}
It doesn't matter what that System object is or what the step function does [except it needs to interact with the UI, in my case, update a canvas to run Conway's Game of Life in the background], the activity is performed slowly and I want it to run faster. But I already specified no wait time in the setInterval, and yet, when I check the profiling tool in Chrome it tells me the whole thing is 80% idle:
Is there a way to make it do less idle time and perform my job more quickly on a best effort basis? Or do I have to make my own infinite loop and then somehow yield back time to the event loop on a regular basis?
UPDATE: It was proposed to use requestIdleCallback, and doing that makes it actually worse. The activity is noticably slower, even if the profiling data isn't very obvious about it, but indeed the idle time has increased:
UPDATE: It was then proposed to use requestAnimationFrame, and I find that once again the slowness and idleness is the same as the requestIdleCallback method, and both run at about half the speed that I get from the standard setInterval.
PS: I have updated all the timings to be comparable, all three now timing about 10 seconds of the same code running. I had the suspicion that perhaps the recursive re-scheduling might be the cause for the greater slowness, but I ruled that out, as the recursive setTimeout call is about the same speed as the setInterval method, and both are about twice as fast as these new request*Callback methods.
I did find a viable solution for what I'm doing in practice, and I will provide my own answer later, but will wait for a moment longer.
OK, unless somebody comes with another answer this here would be my FINAL UPDATE: I have once again measured all 4 options and measured the elapsed time to complete a reasonable chunk of work. The results are here:
setTimeout - 31.056 s
setInterval - 23.424 s
requestIdleCallback - 68.149 s
requestAnimationFrame - 68.177 s
Which provides objective data to my impression above that the two new methods with request* will perform worse.
I also have my own practical solution which allows me to complete the same amount of work in 55 ms (0.055 s), i.e., > 500 times faster, and still be relatively well behaved. Will report on that in a while. But wonder what anybody else can figure out here?
I think this is really dependent on what exactly you are trying to achieve though.
For example, you could initialize your web-worker on loading the page and make it run the background-job, if need be, then communicate the progress or status of the job to the main thread of your browser. If you don't like the use of post-message for communication between the threads, consider user Comlink
Web worker
Comlink
However, if the background job you intend to do isn't something worth a web-worker. You could use the requestIdleCallback API. I think it fits perfectly with what you mentioned here since you can already make it recursive. You would not need a timer anymore and the browser can help you schedule the task in such a way that it doesn't affect the rendering of your page (by keeping everything with 60fps).
Something like =>
function run() {
// whatever you want to keep doing
requestIdleCallback(run)
}
You can read more about requestIdleCallback on MDN.
OK, I really am not trying to prevent others to get the bounty, but as you can see from the details I added to my question, none of these methods allow high rate execution of the callback.
In principle the setInterval is the most efficient way to do it, as we already do not need to re-schedule the next call back all the time. But it is a small difference only. Notably requestIdleCallback and requestAnimationFrame are the worst when you want to be rapidly called back.
So, what needs to be done is instead of executing only a tiny amount of work and then expect to be called back quickly, we need to batch up more work. Problem is we don't know exactly how much work we should batch up before it is too much. That can probably in most cases be figured out with trial and error.
Dynamically one might take timing probes to find out how quickly we are being called back again and preemptively exit the work (loop of some kind) when the time between the call-backs is expired.
I built a nodejs application that should execute several tasks.
My app.js has a function call to the manager module which controls those tasks.
I want to call that function from my app.js and perform those tasks every 30s.
something like:
setInterval(manager.tasks(), 30000);
My question is that if using setInterval could give me any performance problems (slowing down the computer, blocking resources or any other reason)
Is there a more efficient way to do this or is setInterval ok?
it depends on how heavy the work/processing you want to do is, setInterval is async so your code will only be run once every 30 seconds, but at the same time JavaScript is single-threaded, so if you're doing a lot of work in your task, the one time it runs in 30 seconds it may take too long to execute thus blocking resources.
In most cases you should be fine using setInterval, but if you really want to emulate multi-threading or if you're doing too much work in your task, you may want to spawn another child process https://nodejs.org/api/child_process.html process or use the new Worker Threads API https://nodejs.org/api/worker_threads.html instead, but keep in mind its not as simple to implement as a setInterval call
Use node-cron or node-schedule instead
setInterval is implemented in standard node js, you won't have any performance / blocking problems, most libraries also use setInterval
It completely depends on the function you executing inside setInterval. If it is I/O bound operation then you don't need to worry too much because libuv will handle itself But if it is CPU bound then I will suggest you to use child_process api to fork a new child process and do your stuff in to that.
Since there is this function window.performance.now() that returns the current time in microseconds since the page started to load, is there a way to implement it's accuracy in to a more precise setTimeout function
The short answer is no, there isn't. In addition, the millisecond granularity of setTimeout is misleading. Some browsers are far less accurate, although there are workarounds for this. In any case, setTimeout calls are only called after the current call stack finishes executing, which could be much longer than you want. setInterval actually has an interesting behavior where it will queue up multiple calls if they're deferred by other executing code, so that when they execute they'll all execute one after another with no delay in between.
Short answer:no.
Long answer: Javascript doesn't guarantee an exact time-out period, just a minimum time-out period. Both setTimeout() and setInterval() defer the code and execute it when the thread becomes available. Measuring this to microseconds would be pointless.
In my application I found some JavaScript code that is using setInterval with 0 milliseconds, like so:
self.setInterval("myFunction()",0);
Obviously, this does not seem like a good idea to me. Can anyone tell me what will be the behaviour of setInterval here? ("myFunction" makes an AJAX call to the server)
I am asking this because I am having an irregular behaviour in my application. 90% of the times, the application behaves correctly and exactly one call to the server is made. However sometimes, multiple calls are made to the server (until now, maximum is 48 calls) and I am almost certain it is the fault of this line of code.
Browser set a minimal value for the interval. Usualy 10ms, but it can depend on the browser. This means repeat this as fast as I'm possibly allowed. The W3C spec say 4ms : http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#timers
This is correct but probably reveal a design error.
EDIT: By the way, it is bad practice to pass a string to setTimeout/setInterval, pass a function instead as javascript has first class functions.
setInterval(myFunction, 0) calls myFunction continuously with minimum delay. It is almost like calling myFunction in a infinite loop. Except that here you can stop the loop using the clearInterval method.
To have it executed only once with minor delay, use setTimeOut instead:
window.setTimeout(myFunction, 10);
As you're using AJAX, you don't have to use any timers at all - just call the next AJAX request in the Callback (complete/success event) of the current AJAX request.
Post your current code and we might be able to guide you further.
I assume that in myFunction() there is a clearInterval.
Basically, you've set an interval that can happen as often as possible. If the browser executing JavaScript actually gets to the clearInterval part before the next iteration of the interval, then it will be fine. Otherwise, it will happen again and again.
Use setTimeout instead.
setInterval with '0' moves the code execution at the end of the current thread. The code is put to the side, all other code in the thread is executed, and when there is no code for execution, then the side code is executed.
Right now I have a jQuery plugin that adds some extra customization (around how to handle the return data in certain contexts) and polling a server for information and changes. One of the required features is to allow the user set the polling interval. setTimeout (paired with recursion) is the function that is used for creating the constant poll; this is also a requirement.
This is where I am stumped: along with the required functionality noted above, I also have to test if the user-specified value was actually used in the setTimeout. How would I go about doing this from a QUnit perspective?
I have already pondered straight timing the function with Date.getTime(), but the way things are currently set up this isn't an option.
Consider refactoring the code in a way that let's you override the method starting the timeout within your test, allowing you to verify that the correct value is passed, without actually starting the timeout.
If you need to actually call setTimeout, consider using sinon.js to mock setTimeout itself and control what it does instead.