HTML/JavaScript: How to run a loop while running other code? - javascript

I want to have code that simply will count up by one every second or so. However, I also want to be able to run other code alongside it.
Example:
while(true){
Number + 1 + OtherNumber = Number
}
And also be able to run this at the same time:
function onButtonPress() {
OtherNumber++
}
Note: I do not want to increment otherNumber at an interval, but rather on the press of a button.

You can use setInterval:
var intervalId = setInterval(function() {
OtherNumber++;
}, 1000);
It will increase OtherNumber by one approximately every second.
setInterval returns ID of interval, which can be used to stop it:
clearInterval(intervalId);
Demo snippet:
document.body.innerHTML += "Start<br/>";
setInterval(function() {
document.body.innerHTML += "Interval step<br/>";
}, 1000);
document.body.innerHTML += "Look! Code is completed before interval step<br/>";

If you want to run code as two separate threads you will have to use web Workers as Javascript is single threaded and can not run more than one function at a time.
If you create a function
function workForever(){
while(true){
.. do work
}
}
You will completely block all code, no events will get called, no other javascript will be executed. Most browsers will throw up a dialog reporting that a function is taking a long time do you want to kill the page. But your code is stuck in that loop and can only be exited from within the loop itself.
WebWorkers are a good solution to multitasking in the Javascript environment, but you still need to provide some non execution time to allow the webworkers to communicate. The while(true) will block all communication with the workers, in effect making them useless.
SetInterval, setTimeout, requestAnimationFrame will also be blocked. Javascript unfortunately is single threaded and will never be able to run two functions at the same time.

Related

How would you terminate an infinite loop (`setInterval`) in the console?

For instance, we could run
setInterval(function(){console.log("Hello, SO!")}, 2000);
Hello, SO! gets repeated every two seconds in the terminal. There are 6 repeats in the picture below.
Is there a key combination you could press or command you could type to stop the infinite loop in the console?
This is your best bet that I know of.
var interval = setInterval(() => console.log("hello, world"), 2000);
clearInterval(interval);
To kill intervals, you need a handle to them to pass to clearInterval(). In your image, after you execute setInterval(), you can see the handle is returned to the console as 4491. In this way, you can kill it like so:
clearInterval(4491);
Alternatively (and better), you should assign that handle return to a variable so you can kill it programmatically:
let interval = setInterval(() => console.log('Hello, SO!'), 2000);
clearInterval(interval);
Edit:
You can also brute-force. The handle is an int64 number, so it could potentially be enormous, but for almost any app, it'll be small since the handles are incremented. Note that this method could break other packages that rely on intervals.
for (var i = 1; i < 9999; i++) clearInterval(i);
You can stop script execution on the current page using the pause button described here. This will pause all JS on the page though, not just your interval.

setTimeout blocking issue

I'm writing a "Game of Life" in javascript. I have all the logic done in a function called doGeneration(). I can repeatedly call this from the console and everything goes as planned, however, if I put it in a while loop the execution blocks the UI and I just see the end result (eventually).
while (existence) {
doGeneration();
}
If I add a setTimeout(), even with a generation limit of say 15, the browser actually crashes (Canary, Chrome).
while (existence) {
setTimeout(function() {
doGeneration();
},100);
}
How can I call doGeneration() once every second or so without blocking the DOM/UI?
You want setInterval
var intervalId = setInterval(function() {
doGeneration();
}, 1000);
// call this to stop it
clearInterval(intervalId);
I would use requestAnimationFrame(doGeneration). The idea of this function is to let the browser decide at what interval the game logic or animation is executed. This comes with potential benefits.
https://hacks.mozilla.org/2011/08/animating-with-javascript-from-setinterval-to-requestanimationframe/
Rather than using setINterval or setTimeout and assume some random time interval will be enough for the UI to update you shoul/could make the doGeneration smart enough to call itself after dom was updated and if the condition of existence is satisfied.

javascript set interval run as separate thread?

I want to use a timer as a fallback in case I end up in an infinite loop. It seems that set interval is the right way to do this. However, it's not working for me.
From my research, it seems like setInterval should run in a separate thread in the background, but I don't see it.
Why is this behavior happening? And how do I solve this?
var time = 0;
window.setInterval(function(){time++;}, 1000);
while (true) {
//stuff done
if (time >= 5) {
break;
}
}
Browser javascript runs in a single thread. So if you perform something that takes too long - it will freeze browser.
See John Resig article for further details: http://ejohn.org/blog/how-javascript-timers-work/
After you read that article you'll get that your setInterval callback queued to be run in 1000ms after now but only after the current code is finished. It cannot finish though, because of the infinite loop.
zerkms has the correct answer. But I would add that web workers are a way to get some multi-threaded-ish behavior from client side javascript.
var worker = new Worker('my_task.js');
worker.onmessage = function(event) {
console.log("Called back by the worker!\n");
};
The worker runs in a background thread, and you can exchange messages and subscribe to events. It's pretty nifty.
As has been already said - the callback to setInterval doesn't run until the infinite loop finishes. To do what you are trying to achieve - without using web workers - you have to check the time from the loop itself:
var start = Date.now();
while((Date.now() - start) < 5000){
...
}

Using setTimeout to improve responsiveness

When looking to improve a page's performance, one technique I haven't heard mentioned before is using setTimeout to prevent javascript from holding up the rendering of a page.
For example, imagine we have a particularly time-consuming piece of jQuery inline with the html:
$('input').click(function () {
// Do stuff
});
If this code is inline, we are holding up the perceived completion of the page while the piece of jquery is busy attaching a click handler to every input on the page.
Would it be wise to spawn a new thread instead:
setTimeout(function() {
$('input').click(function () {
// Do stuff
})
}, 100);
The only downside I can see is that there is now a greater chance the user clicks on an element before the click handler is attached. However, this risk may be acceptable and we have a degree of this risk anyway, even without setTimeout.
Am I right, or am I wrong?
The actual technique is to use setTimeout with a time of 0.
This works because JavaScript is single-threaded. A timeout doesn't cause the browser to spawn another thread, nor does it guarantee that the code will execute in the specified time. However, the code will be executed when both:
The specified time has elapsed.
Execution control is handed back to the browser.
Therefore calling setTimeout with a time of 0 can be considered as temporarily yielding to the browser.
This means if you have long running code, you can simulate multi-threading by regularly yielding with a setTimeout. Your code may look something like this:
var batches = [...]; // Some array
var currentBatch = 0;
// Start long-running code, whenever browser is ready
setTimeout(doBatch, 0);
function doBatch() {
if (currentBatch < batches.length) {
// Do stuff with batches[currentBatch]
currentBatch++;
setTimeout(doBatch, 0);
}
}
Note: While it's useful to know this technique in some scenarios, I highly doubt you will need it in the situation you describe (assigning event handlers on DOM ready). If performance is indeed an issue, I would suggest looking into ways of improving the real performance by tweaking the selector.
For example if you only have one form on the page which contains <input>s, then give the <form> an ID, and use $('#someId input').
setTimeout() can be used to improve the "perceived" load time -- but not the way you've shown it. Using setTimeout() does not cause your code to run in a separate thread. Instead setTimeout() simply yields the thread back to the browser for (approximately) the specified amount of time. When it's time for your function to run, the browser will yield the thread back to the javascript engine. In javascript there is never more than one thread (unless you're using something like "Web Workers").
So, if you want to use setTimeout() to improve performance during a computation-intensive task, you must break that task into smaller chunks, and execute them in-order, chaining them together using setTimeout(). Something like this works well:
function runTasks( tasks, idx ) {
idx = idx || 0;
tasks[idx++]();
if( idx < tasks.length ) {
setTimeout( function(){ runTasks(tasks, idx); },1);
}
}
runTasks([
function() {
/* do first part */
},
function() {
/* do next part */
},
function() {
/* do final part */
}
]);
Note:
The functions are executed in order. There can be as many as you need.
When the first function returns, the next one is called via setTimeout().
The timeout value I've used is 1. This is sufficient to cause a yield, and the browser will take the thread if it needs it, or allow the next task to proceed if there's time. You can experiment with other values if you feel the need, but usually 1 is what you want for these purposes.
You are correct, there is a greater chance of a "missed" click, but with a low timeout value, its pretty unlikely.

java script for grease monkey loop

what i need is a for or while loop that will re run the code every second
ive tried sleep() but i dont think it is working or i have got it right
Do not try to use a for or while loop for such timed operations. You'll have a hard time with reliable or accurate timing and usually end up railing the CPU, making the computer sluggish.
JavaScript provides the setInterval() function for these kinds of tasks. Also note that Greasemonkey has some caveats about how to use setInterval() and setTimeout().
So the code you want is like:
var timerVar = setInterval (function() {DoMeEverySecond (); }, 1000);
function DoMeEverySecond ()
{
//--- Your code here.
}
//--- When ready to stop the timer, run this code:
clearInterval (timerVar);
timerVar = "";
try
// where yourfunction is a method that contains your loop logic
setTimeout(yourfunction, 1000);
This will invoke the function every 1000 milliseconds without having to embed it into a while or for loop.
put it into your body onload or similar event

Categories

Resources