Javascript webpage stop functioning, unresponsive/crashes - javascript

I'm having an issue with a Javascript assignment task. Essentially what I'm trying to accomplish is a "screensaver" design loop using html5 canvas. When a button is clicked in html, it runs a function that uses random number generation to decide on a shape, location of the shape, shape fill colour and shape stroke style, draws the shape and then loops back around again. The issue I'm currently having is when the button is clicked, the page (I'm using both chrome and firefox) crashes. I understood that this may be because of the loop that I am using, so in response I put a 1.5 second delay on the function- however it still won't function. Any advice on how to improve this would be greatly appreciated.
Thanks :)
(I tried indenting code by 4 spaces, sorry wouldn't work for some reason..?)
HTML:
<button onclick="Screensaver()">Screensaver</button><br>
<div id="Screensaver">
<br><button onclick="screenstart()">Start Screensaver</button><br>
<br><button onclick="screenstop()">Stop Screensaver</button>
</div><br>
<canvas id="myCanvas" width="1000" height="600" style="border:1px solid #47bfff;">
</canvas>
JAVASCRIPT:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var gradient=ctx.createLinearGradient(0,0,canvas.width,0);
//screensaver variables
var loop = 0;
var shapenum = 0;
var fillnum = 0;
var stylenum = 0;
var SS = document.getElementById("Screensaver");
//rectangle
var rectx1 = 0;
var recty1 = 0;
var rectx2 = 0;
var recty2 = 0;
//triangle
var trix = 0;
var triy = 0;
//circle
var circx = 0;
var circy = 0;
var circr = 0;
//radius calculation
var sct = 0;
var scb = 0;
var scl = 0;
var scr = 0;
var scmax = 0;
//SCREENSAVER FROM HERE
SS.style.display = "none";
function Screensaver() {
if (SS.style.display === "" +
"none") {
SS.style.display = "block";
} else {
SS.style.display = "none";
}
}
//loop
function screenstart(){
loop = 1;
while (loop = 1){
setTimeout(screenloop(), 1500);
screenloop();
}
}
function screenstop(){
loop = 0;
}
function screenloop(){
randcal();
ifstatements();
}
//just calculations from here on down

As I said in my comment, the problem is in your screenstart function. There are actually quite a few things wrong in that, but the main one, which causes the crashing/freezing of your browser, is that the loop never actually ends. Javascript is single threaded, that is it can only do one thing at a time - and while the loop should stop when loop is 0 (or would if you'd correctly used == rather than =), this never happens because your code is stuck in a loop, executing screenloop continually (while also scheduling more and more calls to this function later, not that it can ever get to them).
There is a straightforward fix though. Cut down the function to just this:
function screenstart(){
loop = 1;
setInterval(screenloop, 1500);
}
And then do the following in screenloop:
function screenloop(){
if (loop == 1) {
randcal();
ifstatements();
}
}
The most important difference is that you simply schedule screenloop to run every 1.5 seconds, while allowing other events to happen, and other code to run if necessary, in between. Including the possibility of loop being set to 0. And every time screenloop runs, it checks this value, and only does its stuff if the value is 1.

Your current code basically spams the event loop with calls to screenloop().
setTimeout() just schedules a call to that function in 1.5s, but does not hold the loop until then. So basically your loop here just fills up the event loop until the browser crashes.
function screenstart(){
loop = 1;
while (loop = 1){
setTimeout(screenloop(), 1500);
screenloop();
}
}
For animations like yours you may want to look at requestAnimantionFrame(). On a very rough first attempt this could look like this (I did not look though all of your code, whether this actually will work. Depends on different factors, like how long each rendering loop takes etc):
let animationId;
function screenstart(){
randcal();
ifstatements();
animationId = requestAnimationFrame(screenstart);
}
function screenstop(){
cancelAnimationFrame( animationId );
}

Related

Creating a for loop that loops over and over =

So I have a weird problem (as I can do this using dummy code, but cannot make it work in my actual code) -
The concept is simple - I need a for loop that upon hitting its max "I" number reverts "I" to 0 again and creates a loop over and over -
DUMMY CODE:
for(i=0;i<10;i++){
console.log(i);
if(i === 10){
i = 0
}
}
Now for the longer code (sorry)
function reviewF(){
// add ID to each of the objects
reviews.forEach((e, i)=>{
e.id = i
})
// get the elements to be populated on page
var name = document.querySelector('p.name');
var date = document.querySelector('p.date');
var rating = document.querySelector('.rating_stars');
var review = document.querySelector('p.review_content_text');
// reverse the array - so the newest reviews are shown first (this is due to how the reviews where downloaded)
var reviewBack = reviews.slice(0).reverse();
// start the loop - go over each array - take its details and apply it to the elements
/**
* THIS IS WHAT I WOULD LIKE TO LOOP OVER FOREVER
*
* **/
for (let i = 0; i < reviewBack.length; i++) {
(function(index) {
setTimeout(function() {
// document.getElementById('reviews').classList.remove('slideOut')
name.classList.remove('slideOut')
date.classList.remove('slideOut')
rating.classList.remove('slideOut')
review.classList.remove('slideOut')
name.classList.add('slideIn')
date.classList.add('slideIn')
rating.classList.add('slideIn')
review.classList.add('slideIn')
name.innerHTML = reviewBack[i].aditional_info_name;
date.innerHTML = reviewBack[i].Date;
rating.innerHTML = '';
review.innerHTML = reviewBack[i].aditional_info_short_testimonial;
if(reviewBack[i].aditional_info_short_testimonial === 'none'){
reviewBack.innerHTML='';
}
var numberOfStars = reviewBack[i].aditional_info_rating;
for(i=0;i<numberOfStars;i++){
var star = document.createElement('p');
star.className="stars";
rating.appendChild(star);
}
setTimeout(function(){
// document.getElementById('reviews').classList.add('slideOut')
name.classList.add('slideOut')
date.classList.add('slideOut')
rating.classList.add('slideOut')
review.classList.add('slideOut')
},9600)
}, i * 10000)
})(i);
// should create a infinite loop
}
console.log('Loop A')
}
// both functions are running as they should but the time out function for the delay of the transition is not?
reviewF();
EDITS >>>>>>>>
Ok so I have found a hack and slash way to fix the issue - but its not dry code and not good code but it works.....
this might make the desiered effect easier to understand
reviewF(); // <<< this is the init function
// this init2 function for the reviews waits until the reviews have run then
// calls it again
setTimeout(function(){
reviewF();
}, reviews.length*1000)
// this version of the innit doubles the number of reviews and calls it after that amount of time
setTimeout(function(){
reviewF();
}, (reviews.length*2)*1000)
From trying a bunch of different methods to solve this issue something I noticed was when I placed a console.log('Finished') at the end of the function and called it twice in a row (trying to stack the functions running..... yes I know a horrid and blunt way to try and solve the issue but I had gotten to that point) - it called by console.log's while the function was still running (i.e. the set time out section had not finished) - could this have something to do with it.
My apologies for the rough code.
Any help here would be really great as my own attempts to solve this have fallen short and I believe I might have missed something in how the code runs?
Warm regards,
W
Why not simply nest this for loop inside a do/while?
var looping = True
do {
for(i=0;i<10;i++){
console.log(i);
}
if (someEndCondition) {
looping = False;
}
}
while (looping);
I would think that resetting your loop would be as simple as setting "i = 0" like in the dummy code. So try putting the following into your code at the end of the for loop:
if(i === 10){
i = 0;
}

Appending to empty element does not work

I want to display the characters of a string, stored in an array, one by one.
When I call threadsleep(a) using the following code: http://jsfiddle.net/thefiddler99/re3qpuoo/, it appears all at once.
The problem lies somewhere here I presume
for (var i = 0; i < str.length; i++) {
$('#hello').append(str[i])
alert("foo")
sleep(500)
};
The alert shows that everything is working properly except that the interval between each is not present.
I cannot figure out why.
Note: Sleep is a function I have defined that works for the set amount of time
JavaScript is single threaded. It is too busy running round and round your while loop to perform a repaint of the page.
Don't try to write a sleep function. The language isn't suited to it and it just chomps CPU. Rewrite your code to use setInterval or setTimeout instead.
var i = 0;
next();
function next() {
$('#hello').append(str[i]);
i++;
if (i < str.length) {
setTimeout(next, 500);
}
}
Just try with setTimeOut recursion call.
Demo
<script>
var text="This string will be display one by one.";
var delay=500;
var elem = $("#oneByOne");
var addTextByDelay = function(text,elem,delay){
if(!delay){
delay = 500;
}
if(text.length >0){
//append first character
elem.append(text[0]);
setTimeout(
function(){
//Slice text by 1 character and call function again
addTextByDelay(text.slice(1),elem,delay);
},delay
);
}
}
addTextByDelay(text,elem,delay);
</script>

How can I ignore deceleration from event.acceleration in JS?

I'm trying to have an event occur when the phone first starts moving. This triggers just fine. However, I am running into a problem: deceleration is measured similarly to acceleration. When I stop moving the device, I see another spike. Any suggestions on how to ignore that second spike?
The following code gives me "huzzah!" when I first move the phone and when I stop moving it. I only want the trigger on the first movement. I got the pertinent functions and most of the variables defined here. Not the full extent of the script, but all the parts of this functionality.
var elmt = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
var acceleration = eventData.acceleration;
var speed = 0;
speed = round(acceleration.y);
elmt.splice(0,1);
elmt.push(speed);
speedSmoothed=elmt.average();
//Rounding function
function round(val) {
var amt = 10;
return Math.round(val * amt) / amt;
}
//Averaging function for the array
Array.prototype.average=function(){
var sum=0;
var j=0;
for(var i=0;i<this.length;i++){
if(isFinite(this[i])){
sum=sum+parseFloat(this[i]);
j++;
}
}
if(j===0){
return 0;
}else{
return sum/j;
}
}
//trigger
if (speedSmoothed>1.5){
console.log("Huzzah!");
}
a few hours of thinking later, I got a little crafty. Enough to reliably behave like I want it to anyway.
if (speedSmoothed>1.5 && elmt[0]>elmt[4]){
console.log("Huzzah!");
}

How to proper use setTimeout with IE?

For a mockup-webpage used for research on interaction on websites, I created a mockup message-stream using JavaScript. This message stream should show images at pre-set intervals. In Chrome, this code posts the images below one another, at the pre-set intervals. In IE, only the first image is shown. I have already removed the passing of parameters in the window.setTimeout method, but am lost as to what else I need to do to satisfy IE. What else should I do to make all images appear in the pre-set intervals?
My script-section has several global variables:
var updateinterval = 400; // a multiplier (integer) used to
var scrollinterval = 5; // an interval (integer) to wait before scrolling
var point; // integer used to prevent using parameters in window.setTimeout
var interval = [0, 10, 40]; // array of integers creating diversity in intervals
var images = ["r1", "a1", "r2"];// array of strings referring to images to show
The following functions are present:
function trypost(){
point = point + 1;
if(point < interval.length){
//write the required image
document.writeln("<img src='images/"+images[point]+".png'/><br/>");
//time scroll to bottom
var stb = window.setTimeout(scrollToBottom, scrollinterval);
//time next post
var nextupdate = interval[point]*updateinterval;
var tp = window.setTimeout(trypost, nextupdate);
}
}
function scrollToBottom(){
window.scrollBy(0,document.body.scrollHeight);
}
function startpost(){
point = -1;
trypost();
}
window.onload = startpost;
You can use setInterval instead of repeatedly calling setTimeout, setInterval repeats until you call clearInterval.
Also as noted in the comments, document.writeln is from a different decade ;)
You can modify the DOM directly now.
var i=0;
var interval = [0, 10, 400, 10, 1000];
var images = [
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRTiW-7zqLiG1DNq4Tmt6x4j1iBc0FZRBpyYZtIXgDzUy_NHwTv",
"http://img2.wikia.nocookie.net/__cb20120327004334/mrmen/images/a/a0/MrMean.gif",
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRTiW-7zqLiG1DNq4Tmt6x4j1iBc0FZRBpyYZtIXgDzUy_NHwTv",
"http://img2.wikia.nocookie.net/__cb20120327004334/mrmen/images/a/a0/MrMean.gif",
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRTiW-7zqLiG1DNq4Tmt6x4j1iBc0FZRBpyYZtIXgDzUy_NHwTv"
];
for(var i=0; i<interval.length;i++)
var timer = setTimeout(function(img){
var newImg = document.createElement("IMG");
newImg.src = img;
document.getElementById('holder').appendChild(newImg);
}, interval[i], images[i]);
with this HTML
<div id='holder'>
</div>
Running demo
http://jsfiddle.net/W7QXH/4/

JavaScript / Jquery Rotating Slider - Double Delay Issue

with some help I have created a rotating slider using jquery and CSS3, and it seems to be working great except for one thing... The first 'slide' seems to have double the delay on the first play through. Can anyone shed some light on why this might be happening? Any help would be greatly appreciated...
var i = 0;
var z = 0;
delay = 5000;
var el = $('#scroll-script');
var ql = $('#info-box');
var classesb = ['fp-info-one', 'fp-info-two', 'fp-info-three', 'fp-info-four'];
var classes = ['fp-slide-one', 'fp-slide-two', 'fp-slide-three', 'fp-slide-four'];
var interval = setInterval(function () {
el.removeClass().addClass(classes[i]);
i = (i + 1) % 4;
ql.removeClass().addClass(classesb[z]);
z = (z + 1) % 4;
}, delay);
Your anonymous function, the one inside the setInterval, is waiting the same amount of time (your delay) to run initially. You can either:
1) change the anonymous function into a named function, and run that once before executing your interval
2)Run these lines before the setInterval method. Just to emulate that the code inside the anonymous function once.
el.addClass(classes[3]);
ql.addClass(classesb[3]);
You can look inside this fiddle, and see some solutions I have provided.
http://jsfiddle.net/G7NdU/4/

Categories