For loops are disturbing rendering - javascript

I have some pretty simple 3D objects (basically THREE.Sphere which is a parent of 1-30 other THREE.Spheres, with RGB color and no texture) to display in somewhat real time animation.
The rendering is done in no time indeed, but I have some simple iterative calculation (for-loops) that are disturbing my display capabilities.
The rendering itself is not the problem, but the computation for the next frame vertices is what causing the pain
Meaning, when I just run the script, I can see that the for-loops are taking too much time to compute, and just then it goes to the rendering section which is done in no time.
I was thinking of dealing with this problem in a parallel computing manner- running a thread (worker, whatever it is called in JS) that would calculate the for-loop, but I thought that considering my lack of experience in computer graphocs, perhaps there is a more "graphic"ed way of doing so. Meaning a more elegant/performance-improved/natural way of dealing with such a fundamental problem of computer graphics design.

This is the basic idea I am using to do long slow calculations that don't get caught by the watchdog timers and bog down the browser or the render rate.
The basic idea is that you use a javascript generator that allows you to yield in the middle of a computation, and continue later on. Then, I run the generator pump on a timeout chain.
The key to this method is the "yield" operator that saves the function state and returns awaiting a future call to the .next() function. (btw this demo code might have to be re arraged to handle firefoxs forward references)
//function Chain represents the slow code
function *Chain()
{
for(i=0;i<1000000;i++) //this represents a long slow calculation
{
if(i%100==0) //on occassion, yield
yield;
}
}
console.log("starting chain");
gChain=Chain(); //startup and get the next generator pointer
timeout = setTimeout(function () { ChainStart(); }, 1);
//function ChainStart is a pump that runs the generator using a timeout chain so other threads can run
function ChainStart(){
if(gChain.next().done){
clearTimeout(timeout);
console.log("endingchain");
}
else{
clearTimeout(timeout);
timeout = setTimeout(function () { ChainStart(); }, 1);
}
}

Related

Accurate javascript sleep function

I am using javascript to send a bench of request at regular interval (every 5 ms).
I tried to use setTimeout and also sleep function, but none of them have accurate timing.
They ensure that the time interval is >= 5ms but not == 5ms.
Any idea?
It seems that this very difficult to achieve in javascript or even impossible!!
This is the code I am using:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function sendRequest(){
var i;
for (i=1; i<= numberOfRequests; i++){
// send my i^th request here
await sleep(5);
}
}
There isn't any way to provide exact timeouts in any programming language as much as they live in a general purpose multiprogrammed operating system. That happens because the exact moment the operating system will give its time slice to a particular process is just unpredictable.
Furthermore, JavaScript is single-threaded and it works with an event loop system, and the asyncrhonous tasks (such as setTimehout, xhr callback, click listeners and so on) will be executed only after that all the current code is finished. For example, if you have:
setTimeout(() => console.log('hello world'), 500);
for (let i = 0; i<1E100; i++) {
console.log(Math.sqrt(i));
}
Hello world will be only printed only after all the calculations are completed.
Since javascript uses a single threaded event loop there is no way to obtain that accuracy. The events in the event loop are executed when the engine has finished the previous task. If you set a task to be executed after 20 ms (setTimeout, setInterval or any other custom task) the engine will add that task to the event loop then it will try to run any other task from the loop (let's assume a function that takes 25 ms to run). Since javascript is single thread, you can start any other element from the loop, until the 25ms task is finished. In that case, your timeout will start after 25 ms, even if you set it to 20. This is how javascript architecture works.
Even if you implement multi thread (workers, threads etc.) the event loop will still be present in each of them (each thread has its own loop)

Understanding async using setTimeout

I have a UI where I need animations to run smoothly. Every so often, I need to do a semi-large data calculation that makes the animation skip until it is this calculation is completed.
I am trying to get around this by making the data calculation async with setTimeout. Something like setTimeout(calcData(), 0);
The whole code is something like this (simplified):
while (animating) {
performAnimation();
if (needCalc) {
setTimeout(calcData(), 0);
}
}
But I still get a skip in the animation. It runs smoothly when I do not need to do any data calculations. How can I do this effectively? Thanks!
You are seeing the skip because only one javascript thread is run at once. When something is done asynchronously the javascript engine puts it a queue to be ran later, then finds something else to execute. When something in the queue needs to be done the engine will pull it out and execute it, blocking all other operations until it completes.The engine then pulls something else out of its queue to execute.
So if you want to allow your render to run smoothly you must break up your calculation into multiple async calls, allowing the engine to schedule the render operation in between calculations. This is easy to accomplish if you are just iterating over a array, so you can do something like:
var now=Date.now;
if(window.performance&&performance.now){//use performace.now if we can
now=performance.now;
}
function calculate(){
var batchSize=10;//If you have a exceptionally long operation you may want to make this lower.
var i=0;
var next=function(){
var start=now();
while(now()-start<14){//14ms / frame
var end=Math.min(i+batchSize,data.length);
for(;i<end;i++){//do batches to reduce time overhead
do_calc(data[i]);
}
}
if(i<data.length) setTimeout(next,1)//defer to next tick
};
next();
}
calculate();
function render(){
do_render_stuff();
if(animating) {
requestAnimationFrame(render);//use requestAnimationFrame rather then setTimeout for rendering
}
}
render();
Better yet, if you can, you should use WebWorkers which work in a different thread, completely separate from the main js engine. However you are stuck with this if you need to do something you cant do in a WebWorker, such as manipulating the DOM tree.
Firstly, let's talk what's going on in your code:
while (animating) {
performAnimation();
if (needCalc) {
// it should be setTimeout(calcData, 0);
setTimeout(calcData(), 0);
}
}
In line setTimeout(calcData(), 0); really you don't defer calling of calcData function, you call it, because you use () operator after function name.
Secondly, lets think, what's going on when you really make defer calling for calcData in the code above: commonly JavaScript is running in one thread, so, if you have code like this:
setTimeout(doSomething, 0);
while (true) {};
doSomething will never be called, because interpreter of javascript executes while loop forever and it hasn't "free time" to execute other things (even UI) . setTimeout - just say to schedule execution of doSomething when interpreter will be free and it's time to execute this function.
So, when browser executes javascript function, all other stuff become freezing.
Solution:
If you have big data that you need to process, maybe it would be better to make calculations on backend and after send results to frontend.
Usually when you need to make some calculation and render results it's better to use requestAnimationFrame than while loop. Browser will execute function passed in requestAnimationFrame as soon as possible, but also you give browser a time to handle other events. You can see smooth redrawing using requestAnimationFrame for game (step-by-step tutorial here).
If you really want to process huge amount of data at frontend part and you want to make ui works smooth, you can try to use WebWorkers. WebWorkers look like threads in JavaScript, you need to communicate between main UI "thread" and WebWorker by passing messages from one to another and back and calculations on WebWorker don't affect UI thread.
Mostly, your problem boils down to your incorrect usage of setTimeout()
setTimeout(calcData(), 0);
The first argument to setTimeout is a REFERENCE to the function that you wish to call. In your code, you are not referencing the calcData function, you are invoking it because you've included () after the function name.
Second, the fact that you've put 0 for the delay does not mean you will have a 0 second delay before the function runs. JavaScript runs in a single threaded context. The setTimeout function is placed in a queue and executed when the JavaScript engine is available, but no sooner than a minimum of 10ms or the amount you specify (whichever is less).
Realistically, your line should be:
setTimeout(calcData(),10);

Timing in javascript sequencer

I have developed a music sequencer in javascript; something like this: http://stepseq.michd.me/
I have implemented loop using setInterval function in following way:
var Sequencer = {
...
// every step sequencer ...
next: function(callback) {
// restart from begin if arrive to last sequecer step
if(Sequencer.current==Sequencer.steps.length)
Sequencer.current = 0;
// play all sounds in array step contains
if(Sequencer.steps[Sequencer.current].length>0) {
var set = Sequencer.steps[Sequencer.current];
for(var i=0;i<set.length;i++){
set[i].play();
}
}
callback(Sequencer.current);
Sequencer.current++;
},
loop: function(callback) {
Sequencer.interval = $interval(function(){
Sequencer.next(callback);
}, Sequencer.time);
}
}
...
Code below works but i think that there is a better way to implement loop; infact sometimes steps goes out of time. Sequencer.time (time passed to setInterval function) is a time in millisecs (this value is the conversion of a bpm value; for example it can be 125),
Someone can suggest me a better solution?
N.B.: this is a web application angularjs based (for this reason in code above a use $interval insteed of setInterval), but i think that this point is insignificant.
Javascript timer intervals are not guaranteed to run at exactly the time you request, due to the single threaded nature of JS. What you get is a callback that is queued up to run after the interval expires, whenever the engine is free to run it.
John resig has covered this off in some depth:
http://ejohn.org/blog/how-javascript-timers-work/
http://ejohn.org/blog/analyzing-timer-performance/
And from his conclusions, which is going to be important for your app:
If a timer is blocked from immediately executing it will be delayed
until the next possible point of execution (which will be longer than
the desired delay).
I don't really have a better solution for your problem, due to these fundamental issues with timers in JS, but this may at least explain what is happening.

how alert make javascript interrupt? can I do it with code?

I'm procesing a kind of "big" JSON object around of 4000 elements passing for different methods, and I would like to update a div tag with a text showing the process.
But for some strange reason (just tested in Firefox and Chrome), they don't update the DOM object with the text.
$("#estatusBar").text(_item.Centro_de_trabajo);
Both prefer to continue calculating all the data and other process without and dont take the time for update the text. But if I just code an Alert("") in the loop and then in chrome I click on the "selected box" saying ignore all other alerts, chrome suddenly starts updating the text.
So I was thinking if I can "pause" the calculation with some kind of code to stop and update the DOM element and then continue making the other process?
Is this possible or what is an alternative to this strange behavior?
-- EDIT --
this is the code of the loop
$.each(plantillas, function(_index, _item){
updateBar(_item.Centro_de_trabajo);
calculateItem(_item,_index);
a.push("<div class='blockee'><ul>"+ /*temp.join("")*/ t(_item) +"</ul></div>");
});
No you cannot do what alert does. This limitation is really annoying in some cases but if your problem is just a progress for a single long computation then the solution is simple.
Instead of doing alll the records in one single loop break the computation in "small enough" chunks and then do something like
function doit()
{
processBlockOfRecords();
updateProgressBar();
if (!finished()) {
setTimeout(doit, 0);
}
}
setTimeout(doit, 0);
With this approach is also simple to add an "abort" button to stop the computation.
In your example the loop is
$.each(plantillas, function(_index, _item){
updateBar(_item.Centro_de_trabajo);
calculateItem(_item,_index);
a.push("<div class='blockee'><ul>"+ /*temp.join("")*/ t(_item) +"</ul></div>");
});
so the computation could be split with (untested)
function processRecords(plantillas, completion_callback) {
var processed = 0;
var result = [];
function doit() {
// Process up to 20 records at a time
for (var i=0; i<20 && processed<plantillas.length; i++) {
calculateItem(plantillas[processed], processed);
result.push("<div class='blockee'><ul>" +
t(plantillas[processed]) +
"</ul></div>");
processed++;
}
// Progress bar update
updateProgress(processed, plantillas.length);
if (processed < plantillas.length) {
// Not finished, schedule another block
setTimeout(doit, 0);
} else {
// Processing complete... inform caller
if (completion_callback) completion_callback(result);
}
}
// Schedule computation start
setTimeout(doit, 0);
}
You can try using web workers, to defer the calculation to the background, and this should help you out. Web workers were designed to do this very thing (push large calculations to a background thread). However, this may not work in all browsers. Your main concern is IE, and only IE 10 supports it:
Do you want some version of wait or pause or sleep or similar in javascript is that it?
The only way is with
window.setTimeout()
You can pause any function with it.
Check this post too might help:
Sleep/Pause/Wait in Javascript

Combined delayed function calls in Javascript

I am not quite sure what the technical term for this is. I have a GUI with interactive graphics. After the user has interacted with the GUI, I need to perform some CPU intensive action. However, user input is very frequent, so I only want to call the function after e.g. 1000ms of no userinput. Below the pattern that I use:
scheduler = (function(){
var timer;
function exec(call, delay){
clearTimeout(timer);
timer = setTimeout(call, delay);
};
return exec;
})()
I.e. if the 3 calls to scheduler are done right after each other, only the final one will actually be executed:
scheduler(function(){alert('foo')}, 1000);
scheduler(function(){alert('bar')}, 1000);
scheduler(function(){alert('zoo')}, 1000);
It seems to work, but it feels a bit hacky I am a little worried about any caveats of Javascript setTimeout, especially the scoping problems. Does this seem like a reliable pattern I could use on a larger scale? Will the inline function that I pass to scheduler be able to lookup all objects in its lexical scope as usual, when it is called by settimeout? What about if I have several of these scheduler instances? Could they interfere with each other? Is there an alternative way of accomplishing this?
You could opt for using web worker threads instead:
https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers
http://www.html5rocks.com/en/tutorials/workers/basics/
What I would do:
http://jsfiddle.net/gunderson/4XXQ4/1/
var severQueue = [];
var delay;
$("#inputSquare").mousemove(onMouseMove);
function onMouseMove(){
if (delay){
clearTimeout(delay);
}
serverQueue.push("doSomething")
delay = setTimeout(sendToServer, 1000);
}
function sendToServer(){
console.log(serverQueue.length);
delay = null;
$("#inputSquare").addClass("activated");
// do some ajax using serverQueue
// we'll just simulate it with another timeout
for (var i in serverQueue){
serverQueue.pop();
}
onComplete = setTimeout(onAjaxComplete, 1000);
}
function onAjaxComplete(){
$("#inputSquare").removeClass("activated");
}
​
In theory, your solution looks like it will work. There are no scoping problems related to you passing a callback function to your scheduler function; the callback will close over whatever environment it was created in, just like any other function in JavaScript. That being said, scoping rules can be a bit tricky in JavaScript, so make sure that you read up on it.
In practice, there may be some browser-specific issues related to setTimeout that may make this solution unworkable. For example, the frequency at which certain browsers execute setTimeout callbacks may vary such that you'll be waiting longer than you expect for a callback to be executed. All setTimeout callbacks will be executed sequentially; they'll never be executed in parallel. However, you have guarantees as to what order they will be executed in.
All that being said, any major gotcha in your solution will likely have more to do with the callbacks that your registering rather than the way in which you're registering them.
The debounce function in underscore.js does exactly this:
debounce _.debounce(function, wait, [immediate])
Creates and returns a new debounced version of the passed function that will postpone its execution until after wait milliseconds have
elapsed since the last time it was invoked. Useful for implementing
behavior that should only happen after the input has stopped arriving.
For example: rendering a preview of a Markdown comment, recalculating
a layout after the window has stopped being resized, and so on.

Categories