I'm doing a lot of recursion in Javascript, and to keep the stack from overflowing, I've been using setTimeout. Here's a quick theoretical example:
go(){
setTimeout(function(){
x++;
go();
},1);
}
I've also got a function logging x to the console every few seconds, but that isn't the concern. What I'm seeing is that no matter what value I put in for the timeout, for which I've used 1 in the example, the script can only run 1000 times per second. I'm doing recursion on the level of hundreds of millions, so this isn't fast enough. When I set the timeout value to 0, or .1, or 1/10, I still only get approximately 1000 times per second. I've tried using 32 and 64 bit browsers (Chrome and Firefox) to no avail.
How can I kick the speed up a notch? Also, I'm relatively new at all of this, so it'd be awesome if the solution was a simple one.
Oh, forgot to mention: if I remove the setTimeout altogether, I overflow the stack every time.
Thanks for the help!
Your solution doesn't lie in making your current code run, but to rethink the code.
I don't know how you are using recursion in your code, but clearly you are using it wrong.
For any reasonable use of recursion, you would be far from overflowing the stack. If you are making recursive calls to a level of hundreds of millions, that is at least a million times too much.
A common approach when using recursion is to divide the work in half for each level. That way you can handle all the items that you can fit in memory without going deeper than about 30 levels.
I tried something like you did and found the solution! You don't need recursion and the function setTimeout, but all what you need is to use the setInterval function on the function you want by 1 interval repeatedly in for loop. For example if the for loop repeats itself 10 times, then 10 timers will execute the same function every 4 ms. The code will be executed repeatedly more and more quickly.
Your code should look like this for example:
function onload() {
for (var i = 0; i < 10; i++)
setInterval(go, 1);
}
function go() {
x++;
}
JavaScript is single threaded, and setTimeout will put your operation at the end of the queue. Even if you reduce the delay, you still have to wait for the previous operations to complete before the one you added kicks in.
It's not possible to make setTimeout wait less than 4 milliseconds. That is how setTimeout is defined in the HTML standard (official spec here). More likely your problem is with how your code is structured. Show us the rest of your code, maybe we can help sort it out.
Related
I'm using d3.js 3.5.6. How do we tick the force layout in our own render loop?
It seems that when I call force.start(), that automatically starts the force layout's own internal render loop (using requestAnimationFrame).
How do I prevent d3 from making a render loop, so that I can make my own render and call force.tick() myself?
This answer is plain wrong. Don't refer to it, don't use it.
I wrote a new one explaining how to do this correctly. I remember spending days digging into this as I though I had discovered an error. And, judging by the comments and the upvotes, I have managed to trick others—even including legends like Lars Kotthoff—to follow me down this wrong road. Anyways, I have learned a lot from my mistake. You only have to be ashamed of your errors if you do not take the chance to learn from them.
As soon as this answer is unaccepted I am going to delete it.
At first I was annoyed by the lack of code in the question and considered the answer to be rather easy and obvious. But, as it turned out, the problem has some unexpected implications and yields some interesting insights. If you are not interested in the details, you might want to have a look at my Final thoughts at the bottom for an executable solution.
I had seen code and documentation for doing the calculations of the force layout by explicitly calling force.tick.
# force.tick()
Runs the force layout simulation one step. This method can be used in conjunction with start and stop to compute a static layout. For example:
force.start();
for (var i = 0; i < n; ++i) force.tick();
force.stop();
This code always seemed dubious to me, but I took it for granted because the documentation had it and Mike Bostock himself made a "Static Force Layout" Block using the code from the docs. As it turns out, my intuition was right and both the Block as well as the documentation are wrong or at least widely off the track:
Calling start will do a lot of initialization of your nodes and links data (see documentation of nodes() and links(). You cannot just dismiss the call as you have experienced yourself. The force layout won't run without it.
Another thing start will eventually do is to fire up the processing loop by calling requestAnimationFrame or setTimeout, whatever is available, and provide force.tick as the callback. This results in an asynchronous processing which will repeatedly call force.tick, whereby doing the calculations and calling your tick handler if provided. The only non-hacky way to break this loop is to set alpha to below the hard-coded freezing point of 0.005 by calling force.alpha(0.005) or force.stop(). This will stop the loop on the next call to tick. Unless the timer is stopped this way, it will continue looping log0.99 (0.005 / 0.1) ≈ 298 times until alpha has dropped below the freezing point.
One should note, that this is not the case for the documentation or the Block. Hence, the tick-loop started by force.start() will continue running asynchronously and do its calculations.
The subsequent for-loop might or might not have any effect on the result of the force layout. If the timer happens to be still running in the background, this means concurrent calls to force.tick from the timer as well as from the for-loop. In any case will the calculations be stopped once alpha has dropped low enough when reaching a total of 298 calls to tick. This can be seen from the following lines:
force.tick = function() {
// simulated annealing, basically
if ((alpha *= 0.99) < 0.005) {
timer = null;
event.end({type: "end", alpha: alpha = 0});
return true;
}
// ...
}
From that point on you can call tick as often as you like without any change to the layout's outcome. The method is entered, but, because of the low value of alpha, will return immediately. All you will see is a repeated firing of end events.
To affect the number of iterations you have to control alpha.
The fact that the layout in the Block seems static is due to the fact that no callback for the "tick" event is registered which could update the SVG on every tick. The final result is only drawn once. And this result is ready after just 298 iterations, it won't be changed by subsequent, explicit calls to tick. The final call to force.stop() won't change anything either, it just sets alpha to 0. This does not have any effect on the result because the force layout has long come to an implicit halt.
Conclusion
Item 1. could be circumvented by a clever combination of starting and stopping the layout as in Stephen A. Thomas's great series "Understanding D3.js Force Layout" where from example 3 on he uses button controls to step through the calculations. This, however, will also come to a halt after 298 steps. To take full control of the iterations you need to
Provide a tick handler and immediately stop the timer by calling force.stop() therein. All calculations of this step will have been completed by then.
In your own loop calculate the new value for alpha. Setting this value by force.alpha() will restart the layout. Once the calculations of this next step are done, the tick handler will be executed resulting in an immediate stop as seen above. For this to work you will have to keep track of your alpha within your loop.
Final thoughts
The least invasive solution might be to call force.start() as normal and instead alter the force.tick function to immediately halt the timer. Since the timer in use is a normal d3.timer it may be interrupted by returning true from the callback, i.e. from the tick method. This could be achieved by putting a lightweight wrapper around the method. The wrapper will delegate to the original tick method, which is closed over, and will return true immediately afterwards, whereby stopping the timer.
force.tick = (function(forceTick) {
return function() { // This will be the wrapper around tick which returns true.
forceTick(); // Delegate to the original tick method.
return true; // Truth hurts. This will end the timer.
}
}(force.tick)); // Pass in the original method to be closed over.
As mentioned above you are now on your own managing the decreasing value of alpha to control the slowing of your layout's movements. This, however, will only require simple calculus and a loop to set alpha and call force.tick as you like. There are many ways this could be done; for a simple showcase I chose a rather verbose approach:
// To run the computing steps in our own loop we need
// to manage the cooling by ourselves.
var alphaStart = 0.1;
var alphaEnd = 0.005;
var alpha = alphaStart;
var steps = n * n;
var cooling = Math.pow(alphaEnd / alphaStart, 1 / steps);
// Calling start will initialize our layout and start the timer
// doing the actual calculations. This timer will halt, however,
// on the first call to .tick.
force.start();
// The loop will execute tick() a fixed number of times.
// Throughout the loop the cooling of the system is controlled
// by decreasing alpha to reach the freezing point once
// the desired number of steps is performed.
for (var i = 0; i < steps; i++) {
force.alpha(alpha*=cooling).tick();
}
force.stop();
To wrap this up, I forked Mike Bostock's Block to build an executable example myself.
You want a Static Force Layout as demonstrated by Mike Bostock in his Block. The documentation on force.tick() has the details:
# force.tick()
Runs the force layout simulation one step. This method can be used in conjunction with start and stop to compute a static layout. For example:
force.start();
for (var i = 0; i < n; ++i) force.tick();
force.stop();
As you have experienced yourself you cannot just dismiss the call to force.start() . Calling .start() will do a lot of initialization of your nodes and links data (see documentation of nodes() and links()). The force layout won't run without it. However, this will not start the force right away. Instead, it will schedule the timer to repeatedly call the .tick() method for asynchronous execution. It is important to notice that the first execution of the tick handler will not take place before all your current code has finished. For that reason, you can safely create your own render loop by calling force.tick().
For anyone interested in the gory details of why the scheduled timer won't run before the current code has finished I suggest thoroughly reading through:
DVK's answer (not the accepted one) to "Why is setTimeout(fn, 0) sometimes useful?".
John Reisig's excellent article on How JavaScript Timers Work.
(I need a process.nextTick equivalent on browser.)
I'm trying to get the most out of javascript performance so I made a simple counter ...
In a second I make continuous calls to a function that just adds one to a variable.
The code: codepen.io/rafaelcastrocouto/pen/gDFxt
I got about 250 with setTimeout and 70 with requestAnimationFrame in google chrome / win7.
I know requestAnimationFrame goes with screen refresh rate so, how can we make this faster?
PS: I'm aware of asm.js
Well, there's setImmediate() which runs the code immediately, ie as you'd expect to get with setTimeout(0).
The difference is that setTimeout(0) doesn't actually run immediately; setTimeout is "clamped" to a minimum wait time (4ms), which is why you're only getting a count of 250 in your test program. setImmediate() really does run immediately, so your counter test will be orders of magnitude higher using it.
However you may want to check browser support for setImmediate -- it's not available yet in all browsers. (you can use setTimeout(0) as a fallback of course though, but then you're back to the minimum wait time it imposes).
postMessage() is also an option, and can achieve much the same results, although it's a more complex API as it's intended for more doing a lot more than just a simple call loop. Plus there are other considerations to think of when using it (see the linked MDN article for more).
The MDN site also mentions a polyfill library for setImmediate which uses postMessage and other techniques to add setImmediate into browsers that don't support it yet.
With requestAnimationFrame(), you ought to get 60 for your test program, since that's the standard number of frames per second. If you're getting more than that, then your program is probably running for more than an exact second.
You'll never get a high figure in your count test using it, because it only fires 60 times a second (or fewer if the hardware refresh frame-rate is lower for some reason), but if your task involves an update to the display then that's all you need, so you can use requestAnimationFrame() to limit the number of times it's called, and thus free up resources for other tasks in your program.
This is why requestAnimationFrame() exists. If all you care about is getting your code to run as often as possible then don't use requestAnimationFrame(); use setTimeout or setImmediate instead. But that's not necessarily the best thing for performance, because it will eat up the processor power that the browser needs for other tasks.
Ultimately, performance isn't just about getting something to run the maximum number of times; it's about making the user experience as smooth as possible. And that often means imposing limits on your call loops.
Shortest possible delay while still being asynchronous is from MutationObserver but it is so short that if you just keep calling it, the UI will never have chance to update.
So trick would be to use MutationObserver to increment value while using requestAnimationFrame once in a while to update UI but that is not allowed.
See http://jsfiddle.net/6TZ9J/1/
var div = document.createElement("div");
var count = 0;
var cur = true;
var now = Date.now();
var observer = new MutationObserver(function () {
count++;
if (Date.now() - now > 1000) {
document.getElementById("count").textContent = count;
} else {
change();
}
});
observer.observe(div, {
attributes: true,
childList: true,
characterData: true
});
function change() {
cur = !cur;
div.setAttribute("class", cur);
}
change();
Use postMessage() as described in this blog.
In fact, when I use
setTimeout(a(),60);
setTimeout(a(),120);
setTimeout(a(),180);
setTimeout(a(),240);
It is supposed to be 60ms gap between calling's of a functions.
But it isnt, especially when it is fired during page loading or animating elements. In fact that gap gets even 2x longer when browser 'has hard work to do'. In some cases it can be visible easly.
The point of question is - is there any other way to synchronize events or functions in time in javascript?
The timing in setTimeout(a(),60) in simple terms translates to I will run this function no earlier than 60ms, but if I get busy it could be later than that.
Therefore, setTimeout does not promise when the execution will take place, only that it will take place sometime after the given time in milliseconds.
So to answer your question, no there is no way to guarantee execution time with setTimeout but you can load your script after the DOM has loaded so that JavaScript is not busy anymore loading other things. In jQuery you can use the $(document).ready() function for that purpose.
Read this article by John Resig for more information about timing in JavaScript: http://ejohn.org/blog/how-javascript-timers-work/
Try this:
setTimeout(a,60);
setTimeout(a,120);
setTimeout(a,180);
setTimeout(a,240);
Note that the function doesn't have the ()s.
In your particular case, setInterval() might work:
var count = 0, interval = setInterval(function() {
count += 1;
if (count > 4) {
clearInterval(interval);
} else {
a();
}
}, 60);
Note that jQuery has a built-in animation feature that uses the different, better approach of simply treating an animation as a function of time and frequently checking the clock, so an unexpected delay would simply make the animation a bit less smooth.
What are the best practices for moving elements with javascript?
Do you use timeouts or intervals?
Is it bad to have timed events for 10 milliseconds, or will it be precise?
Do you move pixel by pixel, or a certain fraction of the total distance?
If you use intervals, how do you stop the interval when the element is in position?
The last two times I've seen motion in javascript have been with jQuery and Raphael.js, neither of which I can understand the source code of. Are there some good tutorials or code examples anywhere? Is there a simple explanation of the methods jQuery uses?
There is a recent function called requestAnimationFrame which runs a function as soon as possible. This is a good practice since it has been made for animation purposes.
The way it works in terms of coding is the same as setTimeout, e.g. when the function finishes you call requestAnimationFrame.
In the function, you fetch the current time to see how the object should be positioned at that time.
You can cancel a pending function it with cancelRequestAnimationFrame, passing the return value of requestAnimationFrame.
Currently this is not cross-browser and the functions are vendor-prefixed, e.g. webkitRequestAnimationFrame for Chrome.
E.g.: http://jsfiddle.net/pimvdb/G2ThU/1/.
var div = document.getElementById('div');
var animation;
function move() {
var time = Math.round((new Date()).getTime() / 10) % 200;
div.style.left = time + 'px';
animation = requestAnimationFrame(move);
}
document.getElementById("start").onclick = function() {
animation = requestAnimationFrame(move);
}
document.getElementById("stop").onclick = function() {
cancelRequestAnimationFrame(animation);
}
Here you can find a good Javascript Animation tutorial:
http://www.schillmania.com/content/projects/javascript-animation-1
But what you said is right. Jquery Animate uses setTimeout, moving the object based in calculations of duration, position and easing.
Intervals are preferable, I believe, because you only set it once in the code rather than once per frame. It only needs to read the code once and reuse it several times, rather than reading it every time it is created.
10ms is a bit short. The computer can natively support intervals of about 16ms, then more precise timers can be used for faster intervals, however these are very power-consuming. IE9 supports both, depending on the computer's power settings, but ideally you shouldn't need anything faster than 50ms (20 FPS).
I like to move a fraction of the total distance, based on the time that has passed since the animation started. This way, no matter what the speed of the computer and browser, the animation will always take the exact same amount of time. Guaranteed.
Something like:
interval = setInterval(function() {
// do stuff
if( /*animation ended*/) clearInterval(interval);
},time);
jQuery is easy for some, but personally I find nothing beats writing it yourself in plain, old JS. Much easier to understand what's going on exactly, rather than relying on some framework to get it right for you.
I have wrote this code to make seconds (with decisec & centisec) counting up.
You've wasted time <span id="alltime">0.00</span> seconds.
<script type="text/javascript">
function zeroPad(num,count)
{
var numZeropad = num + '';
while(numZeropad.length < count) { numZeropad = "0" + numZeropad; }
return numZeropad; }
function counttwo() {
tall = document.getElementById('alltime').innerHTML;
if(parseFloat(tall) < 1.00) { tnew2 = tall.replace('0.0','').replace('0.',''); }
else { tnew2 = tall.replace('.',''); }
tnum = parseInt(tnew2) + 1;
//check if have to add zero
if(tnum >= 100) { tstr1 = tnum + ''; }
else { tstr1 = zeroPad(tnum,3); }
tlast = tstr1.substr(0,tstr1.length - 2) + '.' + tstr1.substr(tstr1.length - 2);
document.getElementById("alltime").innerHTML = tlast;
}
var inttwo=setInterval("counttwo()",10);
</script>
In HTML document and run.
It works well but when I use Firefox 4 and run the code. Seems like it LAG a bit (stop a bit before counting up) when it's on some numbers (randomly like 12.20, 4.43). I've tried change "counttwo()" to counttwo but that doesn't help.
I have told some of my friends to run on Firefox 4 too. They said it doesn't lag at all. This cause because of my computer ? or My Firefox ? or something else ?
Thanks in advance!
PS. Fiddle here: http://jsfiddle.net/XvkGy/5/ Mirror: http://bit.ly/hjVtXS
When you use setInterval or setTimeout the time interval is not exact for several reasons. It is dependent on other javascript running, the browser, the processor etc. You have to take a reliability of +- 15ms for granted afaik. See also ...
That's a lot of counting, so on some computer, yes, it might lag (if it's a prehistoric one or the user's got his processor really busy with something), also if I'm right, that thing won't work with Chrome's V8, since that script would freeze if you switched tabs, and resume executing only when you return to that tab.
If you're just seeing pauses every so often, you're probably seeing garbage collection or cycle collection pauses.
You can test this by toggling your javascript.options.mem.log preference to true in about:config and then watching the error console's "Messages" tab as your script runs. If the GC/CC messages are correlated with your pauses, then they're the explanation for what you see.
As for why you see it but others don't... do you see the problem if you disable all your extensions?
The problem with setInterval is that it can eventually lead to a back-up. This happens because the JavaScript engine tries to execute the function on the interval (in your case, 10ms), but if ever that execution takes longer than 10ms, the JS engine starts trying to execute the next interval before the current one stops (which really just means it queues it up to run as soon as the previous callback finishes).
Since JavaScript executes single-threaded (with the exception of web workers in HTML 5), this can lead to pauses in your UI or DOM updates because it is continuously processing JavaScript callbacks from your setInterval. In worst case scenarios, the whole page can become permanently unresponsive because your stack of uncompleted setInterval executions gets longer and longer, never fully finishing.
With a few exceptions, it is generally considered a safer bet to use setTimeout (and invoking the setTimeout again after execution of the callback) instead of setInterval. With setTimeout, you can ensure that one and only one timeout is ever queued up. And since the timers are only approximate anyway (just because you specify 10ms doesn't mean it will happen at exactly 10ms), you don't typically gain anything from using setInterval over setTimeout.
An example using setTimeout:
var count = function(){
// do something
// queue up execution once again
setTimeout(count, 10);
};
count();
One reason why you may see pauses on some browsers, and not others, is because not all JavaScript engines are created equal :). Some are faster than others, and as such, less likely to end up with a setInterval backup.
Different browsers use different JavaScript engines, so it's possible that this code just finds a spot where Firefox's JägerMonkey scripting engine has some problems. There doesn't seem to be any obvious inefficiencies in the counting itself..
If it's working on your friends' installs of FF4, then it's probably just an isolated problem for you, and there isn't much you'll be able to do by changing the code.