Page freezes when 3 second pause is inside a loop - javascript

When i loop through an array in javascript i have it pause for 3 seconds after each item. It does this successfully, but it freezes the webpage until the array completes.
function launchTutorial() {
HideFloatingMenu(); //freezes on page and it doesn't when i comment out the subsequent array loop
//highlightElement("diLeftColumn");
//the classes of each element to highlight in the tutorial
var tutorialClasses = [
"diLeftColumn",
"diMiddleColumn",
"diRightColumn"
];
var threeSec = new Date().getTime() + 3000;
for (var i = 0; i < tutorialClasses.length; i++) {
//$.each(tutorialClasses, function (key, value) {
if (i != 0) {
var now = new Date().getTime();
if (now >= threeSec) {
highlightElement(tutorialClasses[i]);
threeSec = new Date().getTime() + 3000;
}
else {
i = i - 1; //go back to this item if it hasn't been 3 seconds
}
}
else {
highlightElement(tutorialClasses[i]);
threeSec = new Date().getTime() + 3000;
}
}
}
I have tried setTimeout(), setInterval(0, delay(), 2 different custom sleep functions, and a while loop. none of them worked.

Use this. In javascript, when you do a while loop that takes time x, the whole page freezes for that time x. So using a while loop is no option. But you can use the function setTimeout like this. This will run the printNextElement function every 10 seconds (in my example).
At the console.log place, do your logic. And change the 10000 to your time.
const ar = ['Hello', 'World'];
let index = 0;
const printNextElement = () => {
console.log(ar[index]);
index += 1;
if(ar.length === index) {
return;
}
window.setTimeout(printNextElement, 10000);
};
printNextElement();

Related

infinitetly loop array with setTimeout javascript

I have an array of strings that I'm passing to a for loop with a setTimeout inside.
I've tried to for(; ;) and while(true) the function but this just causes the browser to crash.
I've also tried adding an if statement inside the function
if (x == links.length) { loopUrls() }
Which works kind of but skips the entire interval section of the function, cycling the entire array infinitely with no wait.
function loopUrls() {
for (var x = 0, ln = links.length; x < ln; x++) {
setTimeout(function (y) {
document.getElementById('ifURLS').src = links[y];
},x * 500,x);
}
};
loopUrls();
The aim is to have a list of urls that infinitely assigned to the iframe to show reports on a sreen. (the time interval is just small for testing purposes)
There is no need to have multiple timeouts. You can achieve this using setInterval which executes a function every x amount of time. Then in that funciton you keep a state of the current url so you can show the next time the function is run
// creates a function that iterates over the array and every time its called returns the next element
function createIterator(array){
let sourceArray = [...array];
// starts at the end so it resets automatically
let topIndex = sourceArray.length;
let currentIndex = topIndex - 1;
return function (){
currentIndex++;
// if the limit is reached, its reseated
if (currentIndex === topIndex) {
currentIndex = 0;
}
return sourceArray[currentIndex];
}
}
// your urls
let urls = ["a", "b", "c"];
// uses the function to create the iterator
let iterator = createIterator(urls);
setInterval(function() {
let currentUrl = iterator();
document.getElementById('ifURLS').src = currentUrl;
},1000);
No need for loops, as the iterator handles seamlessly
If I understand correctly, you want for every link to have some function that is being executed every X milliseconds.
In order to achieve this I think it's better to use setInterval.
You can do something like:
links.forEach((link) => {
setInterval(() => {
//do something every X milliseconds
}, X)
})
a way to do that :
// const links = [ ... ]
const myImg = document.queryselector('#ifURLS')
function LoadImg()
{
let
indx = 0
, let refIntv =
setInterval( ()=>
{
myImg.src = links[indx++]
if (indx >= links.length)
clearInterval( refIntv )
}
, 5000 ) // 5s delay
}

Best way to initialize html elements in JavaScript for reusability?

The way I did this was by getting the html elements and declaring them as global const variables inside a function() {} that encapsulates the whole program. It works, but I'm unsure if this is good practice. Is there a way to allow reusability of an element without using an omnipresent function() {} or will this be fine?
My Code:
document.addEventListener('DOMContentLoaded', function() {
//The global const elements from HTML doc
const square = document.getElementsByClassName("square");
const mole = document.getElementsByClassName("mole");
const timeLeft = document.getElementsByClassName("time-left")[0]; //# for id elements
//Initialize score, result, and time
let score = document.getElementsByClassName("score")[0];
let result = 0;
let currentTime = timeLeft.textContent;
//Call countDown function every 1000 milliseconds or 1 second
let timerId = setInterval(countDown, 1000);
function main() {
//Add an event listener for each square called mouseup
for (let i = 0; i < square.length; i++) {
square[i].addEventListener("mouseup", checkHit);
}
moveMole()
}
//Once the event triggers, check if val of current square equals to hitPosition
//If it is, update result and hitPosition
function checkHit(event) {
if (this.id === hitPosition) {
result = result + 1;
score.textContent = result;
hitPosition = null;
}
}
//Move mole to a random square every 1000 milliseconds
function moveMole() {
let timerId = null;
timerId = setInterval(randomSquare, 1000);
}
//Choose a randomSquare to put the mole
function randomSquare() {
//Remove mole from the class name to make sure there isn't any forgotten divs that were used for styling
for (let i = 0; i < square.length; i++) {
square[i].classList.remove("mole");
}
//Math.floor rounds down
//math.random() * 9 uses a position from 1 to 9
let randomPosition = square[Math.floor(Math.random() * 9)];
//Set the mole to the randomPostion
randomPosition.classList.add("mole");
//Assign the id of the randomPositon to hitPosition for comparing later
hitPosition = randomPosition.id;
}
//Counts our timer down
function countDown() {
//Decrement currentTime and show currentTime
currentTime--;
timeLeft.textContent = currentTime;
//If currentTime is 0
//Clear the timer set by the setInterval method
//Stops the execution of randomSquare
//Alert user of final score
//Reset time and result
if (currentTime === 0) {
alert("GAME OVER! Your final score is " + result);
timeLeft.textContent = 30;
currentTime = timeLeft.textContent;
result = 0;
score.textContent = result;
}
}
main();
})
As far as I'm concerned, the code looks fine but make sure to look at other people and see what they're doing.

How do I delay this code running in JavaScript?

I have written this code to change an image:
change = function(){
for (r=0; r<6; r++){
for (i = 0; i < 6 ; i++) {
setInterval(imgfile(number=i+1), 5000);
}
}
}
imgfile= function(number){
a = 'document.getElementById("imgdiv").src = "images/'+number+'.svg"';
eval(a);
}
The function change() is called when a button is clicked.
When I press the button the image changes straight to 6.svg, when I want it to go through the images 1, 2, 3, 4, 5, 6 and to repeat it 6 times. When I change setInterval to change.setInterval or imgfile.setInterval it doesn't work at all. How do I fix this?
change = function(i=0){
imgfile(i%6+1);//change image
if(i<36) setTimeout(change,5000,i+1);//next image in 5 seconds
}
imgfile= function(number){
document.getElementById("imgdiv").src = "images/"+number+".svg";//no need to use ev(i||a)l
}
Instead of loop/interval mess you can simply start a timeout that restarts itself after changing the image... This code will loop over 6 images with a delay of 5 seconds and that 6 times...
Something like this, perhaps?
var index, imgCount, loopCount, imgTag, countdown;
index = 0;
imgCount = 6;
loopCount = 6;
imgTag = document.getElementById('imgdiv');
countdown = function () {
if (index < imgCount * loopCount) {
imgTag.src = 'images/' + index % imgCount + '.svg';
index = index + 1;
setTimeout(countdown, 5000);
}
};
countdown();
Here we're avoiding the double loop and using modular math (index % imgCount) to get the right file number.
For another question I wrote a nice utility function that has quite a number of uses, but can also handle this scenario very easily. The main issue is that there is no time elapsing between the different delays being set. So you are setting 6 different actions to all happen within 5000ms, and all will occur at the same moment.
Here's my original answer
Here's the utility function for that answer, along with its application to your problem.
function doHeavyTask(params) {
var totalMillisAllotted = params.totalMillisAllotted;
var totalTasks = params.totalTasks;
var tasksPerTick = params.tasksPerTick;
var tasksCompleted = 0;
var totalTicks = Math.ceil(totalTasks / tasksPerTick);
var initialDelay = params.initialDelay;
var interval = null;
if (totalTicks === 0) return;
var doTick = function() {
var totalByEndOfTick = Math.min(tasksCompleted + tasksPerTick, totalTasks);
do {
params.task(tasksCompleted++);
} while(tasksCompleted < totalByEndOfTick);
if (tasksCompleted >= totalTasks) clearInterval(interval);
};
// Tick once immediately, and then as many times as needed using setInterval
if (!initialDelay) doTick();
if (tasksCompleted < totalTicks) interval = setInterval(doTick, totalMillisAllotted / totalTicks);
}
// Do 6 actions over the course of 5000 x 6 milliseconds
doHeavyTask({
totalMillisAllotted: 5000 * 6,
totalTasks: 6,
tasksPerTick: 1,
initialDelay: false, // Controls if the 1st tick should occur immediately
task: function(n) { console.log('Set image to "images/' + (n + 1) + '.svg"'); }
});
You want to do setTimeout().
setTimeout pauses for the millesecond value and then does the code. Where setInterval runs the code every whatever milleseconds.
Yeah, don't do change.setInterval or whatever, it is just setInterval.
An example for you would be this inside the for loop to replace the setInterval function.
setTimeout(imgfile(i+1), 5000);

something wrong when i append src to images every iterate for every N seconds

Something goes wrong while i do this with my javascript code
function sleep(delay) {
var start = new Date().getTime();
while (new Date().getTime() < start + delay);
}
//submit data with jQuery AJAX
function onSuccess(data) {
var millisecondsToWait = $("#range").val() * 1000;
obj= JSON.parse(data)
for (var x of obj.Images_Url)
{
$("#left_image").attr('src', x.Item1);
$("#right_image").attr('src', x.Item2);
sleep(millisecondsToWait);
}
so what executed is only the last item in obj.Images_Url and the others are not
for example let say we have json string as this
"Images_Url":[{"Item1":"url1","Item2":"url2"},{"Item1":"url3","Item2":"url4"},{"Item1":"url5","Item2":"url6"}]
what only appear is images with url5 and url6
i don't know why is that happening
but i assume that the browser or the render hangup since i'm not using any threads or Tasks ,So Please any one got any idea how to fix this
Rendering occurs when the execution queue has been emptied and that is when your code runs to completion. Therefore, you will only see the last 2 images.
You could do something like this:
let numbersToShow = [1, 2, 3, 4, 5, 6, 7],
left = document.getElementById('left'),
right = document.getElementById('right');
showNumbersByPairAtInterval(numbersToShow, 2000);
function showNumbersByPairAtInterval(numbersToShow, interval, index) {
index = index || 0;
let slice = numbersToShow.slice(index, index + 2),
nextIndex = index + 2;
left.textContent = slice[0];
right.textContent = slice[1];
if (nextIndex <= numbersToShow.length - 1) {
setTimeout(showNumbersByPairAtInterval.bind(
null,
numbersToShow,
interval,
nextIndex
), 2000);
}
}
<span id="left"></span>
<span id="right"></span>
If you're just trying to iterate through the array of image url's at a timed pace you could do something like this, which would be at 1 second intervals:
var obj = JSON.parse(data);
var k = 0;
var total = obj.Images_Url.length;
setInterval(function () {
if (k < total) {
$("#left_image").attr('src', obj.Images_Url[k].Item1);
$("#right_image").attr('src', obj.Images_Url[k].Item2);
k++;
}
}, 1000);

How to create pause or delay in FOR loop?

I am working on a website, where I need to create a pause or delay.
So please tell me How to create pause or delay in for loop in javascript or jQuery
This is a test example
var s = document.getElementById("div1");
for (i = 0; i < 10; i++) {
s.innerHTML = s.innerHTML + i.toString();
//create a pause of 2 seconds.
}
You can't use a delay in the function, because then the change that you do to the element would not show up until you exit the function.
Use the setTimeout to run pieces of code at a later time:
var s = document.getElementById("div1");
for (i = 0; i < 10; i++) {
// create a closure to preserve the value of "i"
(function(i){
window.setTimeout(function(){
s.innerHTML = s.innerHTML + i.toString();
}, i * 2000);
}(i));
}
var wonderfulFunction = function(i) {
var s = document.getElementById("div1"); //you could pass this element as a parameter as well
i = i || 0;
if(i < 10) {
s.innerHTML = s.innerHTML + i.toString();
i++;
//create a pause of 2 seconds.
setTimeout(function() { wonderfulFunction(i) }, 2000);
}
}
//first call
wonderfulFunction(); //or wonderfulFunction(0);
You can't pause javascript code, the whole language is made to work with events, the solution I provided let's you execute the function with some delay, but the execution never stops.
I tried all one, but I think this code is better one, it is very simple code.
var s = document.getElementById("div1");
var i = 0;
setInterval(function () {s.innerHTML = s.innerHTML + i.toString(); i++;}, 2000);
if you want to create pause or delay in FOR loop,the only real method is
while (true) {
if( new Date()-startTime >= 2000) {
break;
}
}
the startTime is the time before you run the while
but this method will cause the browsers become very slow
It is impossible to directly pause a Javascript function within a for loop then later resume at that point.
This is how you should do it
var i = 0;
setTimeout(function() {
s.innerHTML = s.innerHTML + i.toString();
i++;
},2000);
The following code is an example of pseudo-multithreading that you can do in JS, it's roughly an example of how you can delay each iteration of a loop:
var counter = 0;
// A single iteration of your loop
// log the current value of counter as an example
// then wait before doing the next iteration
function printCounter() {
console.log(counter);
counter++;
if (counter < 10)
setTimeout(printCounter, 1000);
}
// Start the loop
printCounter();
While several of the other answers would work, I find the code to be less elegant. The Frame.js library was designed to solve this problem exactly. Using Frame you could do it like this:
var s = document.getElementById("div1");
for (i = 0; i < 10; i++) {
Frame(2000, function(callback){ // each iteration would pause by 2 secs
s.innerHTML = s.innerHTML + i.toString();
callback();
});
}
Frame.start();
In this case, it is nearly the same as the examples that use setTimeout, but Frame offers a lot of advantages, especially if the you are trying to do multiple or nested timeouts, or have a larger JS application that the timeouts need to work within.
I am executing a function where I need access to the outside object properties. So, the closure in Guffa solution doesn't work for me. I found a variation of nicosantangelo solution by simply wrapping the setTimeout in an if statement so it doesn't run forever.
var i = 0;
function test(){
rootObj.arrayOfObj[i].someFunction();
i++;
if( i < rootObj.arrayOfObj.length ){
setTimeout(test, 50 ); //50ms delay
}
}
test();
The way I found was to simply use setInterval() to loop instead. Here's my code example :
var i = 0;
var inte = setInterval(() => {
doSomething();
if (i == 9) clearInterval(inte);
i++;
}, 1000);
function doSomething() {
console.log(i);
};
This loops from 0 to 9 waiting 1 second in between each iteration.
Output :
0 1 2 3 4 5 6 7 8 9
It is not possible to pause a loop. However you can delay the execution of code fragments with the setTimeout() function. It would not make a lot of sense to pause the entire execution anyway.
I am using while loop and check the pause variable to check the user pause/resume the code.
var pause = false;
(async () => {
for (let index = 0; index < 1000; index++) {
while (pause) {
await new Promise((res) => setTimeout(res, 1000));
console.log("waiting");
}
await new Promise((res) => setTimeout(res, 1000));
console.log(index);
}
})();
const pausefunc = async () => {
pause = true;
};
const playfunc = () => {
pause = false;
};
<button onclick="playfunc()">Play</button>
<button onclick="pausefunc()">Pause</button>
I used a do...while loop to put a delay in my code for a modal dialog that was closing too quickly.
your stuff....
var tNow = Date.now();
var dateDiff = 0;
do {
dateDiff = Date.now() - tNow;
} while (dateDiff < 1000); //milliseconds - 2000 = 2 seconds
your stuff....

Categories

Resources