How to suspend JavaScript to allow render - javascript

I have a little script that runs a simulation, of which I want to render the results 'live':
for ( i < simulation steps ) {
do_simulation();
render_with_flot();
}
I noticed that the plot only gets rendered after the last step.
Is there a way to 'suspend' javascript somehow to allow the rendering to run after each iteration?
Or is there a way to make flot run synchronously?
Or do I need to set my own timeouts for each iteration of the for-loop? This seems like kind of a hassle.

Depends how fast it needs to run, but the best way would be to use SetInterval
Pseudocode / hand-written-javascript-that-probably-doesnt-run:
var PerformedSteps;
var Interval;
PerformedSteps = 0;
Interval = setInterval(work, 1000/60); //60 times/second
function work()
{
PerformedSteps++;
if (PerformedSteps == simulation_steps)
{
clearInterval(Interval);
return;
}
do_simulation();
render_with_flot();
}

As an alternative to #PhonicUK's solution, you could do a setTimeout() at the end of work() to schedule the next call to work(), giving the rendering a chance to happen & not tying yourself to any particular refresh rate.

Related

Number-count-up animation in a non-blocking way

I am trying to count a number up to a certain target value in an animation-like style. The environment is Titanium on iOS. I do that as follows.
function countNumberUp(label) {
label.currentVal = label.currentVal ? label.currentVal : 0;
setTimeout(function() {
if (label.currentVal < label.targetVal) {
label.currentVal += 1;
label.setText(label.currentVal);
countNumberUp(label);
}
}, 5);
}
label is an instance of Ti.UI.Label.
First problem I see is that the label.setText()-method is veeery slow. Would be cool if the number counts up in a rush but it's only like 5 steps per second even if I vary the second parameter of setTimeout().
The other thing is that the animation totally blocks die Main/UI thread of iOS and the UI hardly accepts any actions until the animation has finished. Seems like setTimeout does not run in a seperate thread.
Does anyone of you know a better way to do this?
Btw. I have also tried setInterval() but it doesn't seem any better.
Try this example:
function countNumberUp(label){
var interval = setInterval(function(){
if(label.currentVal==label.targetVal){
clearInterval(interval);
}else{
label.text=label.currentVal;
label.currentVal++;
}
//remove self-calling contNumberUp(label);
}, 50);
//5ms delay its cause bad performance
}

Reducing Jitter in HTML5/Javascript App

I'm building for a hobby a metronome in JavaScript/HTML5 (should be eventually a FirefoxOS app). The problem I have is Jitter, which is a no-go for Metronomes. I understand that JavaScript is single-threaded and no controls about process priority exist. This is what I have:
function tick() {
var next_tick_bpm = parseInt(document.getElementById("bpm").value);
if (started) {
if (next_tick_bpm > 0) {
var next_tick_ms = 60000 / next_tick_bpm;
beep();
setTimeout(tick, next_tick_ms);
} else {
toggle();
}
}
}
Is there something else besides setTimeout (I also tried setInterval with the same results)? Maybe some native browser code for more precise timers?
Thanks,
Johannes
Since JS runs on the UI thread and shares it with all other activity, you absolutely cannot remove jitter with simple tools like timeout and interval. The problem is that these merely put you into the queue periodically, and always in the back.
Instead, you should look at Web Workers, which offer a mechanism for pushing long running tasks (like a metronome) off the main thread.
Some good info here:
https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers
You could try something like this:
function start(speed) {
return setInterval(beep, 60000/speed);
}
function stop(iid) {
clearInterval(iid);
}
When you want to start it, do something like:
// Start
var metronome = start(100);
// Stop
stop(metronome);
If nothing blocks the UI thread, the setInterval should give you good results.

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

How do I regularly check the state of a page without refreshing?

I'm pretty new to (javascript) programming and I'm trying to get something automated.
There is a page that contains a countdown timer, and I want my greasemonkey script to automatically do some actions if the condition is met.
I've got this right now:
var timer = document.getElementById('timer_4975');
if (timer.innerHTML < "00:00:20"){
//Some actions
}
But this only checks the condition once when the script is loaded, when the timer goes under 00:00:20, it doesn't detect the condition is met and doesn't go to action.
Can someone guide me in the right direction?
Thanx in advance!
You can use the setTimeout or setInterval functions to perform this task.
setInterval will perform a task regularly, which is probably more suited to what you want to achieve.
Something like:
var timer = document.getElementById('timer_4975');
var intervalHandle = setInterval(function() {
if (timer.innerHTML < "00:00:20"){
//Some actions
clearInterval(intervalHandle);
}
},1000);
would check every second (1000ms). Change the 1000 value to increase or decrease the frequency of checking... once a second is likely to be often enough.
You will have to use setInterval() to execute your code more than once:
setInterval(function() {
if(timer.innerHTML < "00:00:20") {
//Some actions
}
}, 5000); //Execute this function each 5 seconds.

How do I allow a webpage to update while a javascript is running?

There has to be an easy way to do this, but I'm new to JS.
I have a javascript program that (1) takes user input, (2) updates the webpage based on that input, then (3) performs a lengthy calculation. The trouble is that the webpage doesn't register the update till after the lengthy calculation. Isn't there a way to pause execution so that the page can update before the long calculation?
I've tried setTimeout and window.setTimeout, but they made no difference.
The program is for playing a game: the user inputs a move, the script updates the position, then calculates its next move. postMessage prints text messages using div.innerHTML; buttonFn takes the input from the user, updates the position, prints a message, then starts the computer calculating.
function buttonFn(arg){
var hst = histButt;
hst.push(arg);
var nwmv = hst.clone();
postMessage("New move: " + nwmv.join());
if(status == opposite(comp) && !pauseQ){
var mvsposs = movesFromPos(posCur,status);
if(mvsposs.has(nwmv)){
updatePosCur(nwmv);
//waitasec();
if(comp == status && !pauseQ){
compTurn();
};
}
else{
histButt = nwmv;
};
};
};
yes there is, call your function like this. Using setTimeout will allow a page reflow prior to your JS executing.
function buttonFn(arg){
var hst = histButt;
hst.push(arg);
var nwmv = hst.clone();
postMessage("New move: " + nwmv.join());
if(status == opposite(comp) && !pauseQ){
var mvsposs = movesFromPos(posCur,status);
if(mvsposs.has(nwmv)){
updatePosCur(nwmv);
//waitasec();
if(comp == status && !pauseQ){
setTimeout(function(){
compTurn();
},0);
};
}
else{
histButt = nwmv;
};
};
};
Remember, JS is very event driven friendly. If you can move things off, and call them later do it. Thats the only way we can support multi-threaded like behavior.
setTimeout
If you only need to support modern browsers (or if you use a transpiler), you can now use ES6 features to make this much easier and more in the style the original questioner was trying to do. (I realize the question is 8 years old - no harm in a new, more current answer!)
For example you can do something like this:
// helper function to use a setTimeout as a promise.
function allowUpdate() {
return new Promise((f) => {
setTimeout(f, 0);
});
}
// An infinitely looping operation that doesn't crash the browser.
async function neverStopUpdating(someElement) {
let i = 0;
while (true) {
someElement.innerText = i;
i++;
await allowUpdate();
}
}
If you're trying to do a hard computation you'll want to make sure not to do this await too frequently - in this example, in Chrome at time of writing, i only increments by about 150 per second because the context switch of a setTimeout is not fast (where you'd get hundreds of thousands in a second if you didn't yield for updates). You'd likely want to find a balance, either always perform some number of iterations before allowing an update, or maybe eg. call Date.now() in your loop and yield for an update whenever 100ms have passed since the last time you allowed an update.
You can do the update, wait for a bit of time, than do the calculation.
OR
You can use webworkers on browsers that support them.
Without having actual code, that is the best answer that I can give you.
JavaScript is single threaded. If you do your calc server side you could get the results via ajax which is called asynchronously, not blocking your ui.

Categories