I apologise if my question seems simple, I am still trying to figure out JavaScript. I am building a website where I want the contents of a <p>
to constantly change. I want it to loop over the contents of an array defined in my javascript code. However, when I put everything in a while (true)
(because I want it to happen constantly), the <p>
content never changes and the page is stuck on loading.
Here is the code I have so far:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="about.css">
<meta charset="UTF-8">
<title>My Site</title>
</head>
<script>
function changeDynamicText() {
var descriptions = ['list', 'of', 'strings', 'to', 'loop', 'over'];
let i = 0;
while (true) {
window.setTimeout(function() {
document.getElementById("dynamicline").innerHTML = descriptions[i];
}, 600);
i = i + 1;
if (i >= descriptions.length) i = 0;
}
}
</script>
<body onload="changeDynamicText()">
<p id="dynamicline">Starting Text</p>
</body>
</html>
I apologise if my question seems simple, I am still trying to figure out JavaScript. I am building a website where I want the contents of a <p>
to constantly change. I want it to loop over the contents of an array defined in my javascript code. However, when I put everything in a while (true)
(because I want it to happen constantly), the <p>
content never changes and the page is stuck on loading.
Here is the code I have so far:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="about.css">
<meta charset="UTF-8">
<title>My Site</title>
</head>
<script>
function changeDynamicText() {
var descriptions = ['list', 'of', 'strings', 'to', 'loop', 'over'];
let i = 0;
while (true) {
window.setTimeout(function() {
document.getElementById("dynamicline").innerHTML = descriptions[i];
}, 600);
i = i + 1;
if (i >= descriptions.length) i = 0;
}
}
</script>
<body onload="changeDynamicText()">
<p id="dynamicline">Starting Text</p>
</body>
</html>
Help of any kind is greatly appreciated.
Share edited Jun 3, 2019 at 6:05 Ramesh 2,4132 gold badges24 silver badges44 bronze badges asked Jun 3, 2019 at 0:00 Roshan PrabhakarRoshan Prabhakar 1741 silver badge10 bronze badges 2-
2
JavaScript is single-threaded. The call to
setTimeout()
returns immediately. Your code as written will just run and run and run, waiting for nothing. – Pointy Commented Jun 3, 2019 at 0:04 - in fact it prevents the page from drawing! ( ie from being drawn, that is rendered on the screen ). – Bekim Bacaj Commented Sep 6, 2019 at 18:46
5 Answers
Reset to default 3When you use while(true), it will block the JavaScript event loop and therefore no longer render the rest of the body.
You can achieve what you're trying to do by working asynchronously. You already did use setTimeout in there, but you could also use setInterval to trigger the method on a recurring basis.
function changeDynamicText() {
var descriptions = ['list','of','strings','to','loop','over'];
let i = 0;
setInterval(function () {
document.getElementById("dynamicline").innerHTML = descriptions[i];
i = i + 1;
if (i >= descriptions.length) i = 0;
}, 600);
}
You can use setInterval
instead.
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="about.css">
<meta charset="UTF-8">
<title>My Site</title>
</head>
<script>
function changeDynamicText() {
var descriptions = ['list','of','strings','to','loop','over'];
let i = 0;
setInterval(() => {
document.getElementById("dynamicline").innerHTML = descriptions[i];
i = (i + 1) % descriptions.length;
}, 600)
}
</script>
<body onload="changeDynamicText()">
<p id="dynamicline">Starting Text</p>
</body>
</html>
You can easily do this with setInterval
instead of setTimeout
. Use setInterval
when you need something to constantly do something in periods of time.
And I moved the i
manipulation inside of the interval because you want that to execute each time the function gets called.
Also, it's just a really good habit to get into to put your script tags as the very last element of the body in the HTML document. This way you can ensure that all DOM content has loaded before attempting to manipulate the DOM.
Here is a JSFiddle with the code below: https://jsfiddle/mparson8/41hpLaqw/2/
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="about.css">
<meta charset="UTF-8">
<title>My Site</title>
</head>
<body onload="changeDynamicText()">
<p id="dynamicline">Starting Text</p>
<script>
function changeDynamicText() {
var descriptions = ['list','of','strings','to','loop','over'];
let i = 0;
let interval = window.setInterval(function () {
document.getElementById("dynamicline").innerHTML = descriptions[i];
i = i + 1;
if (i >= descriptions.length) i = 0;
}, 600);
}
changeDynamicText();
</script>
</body>
</html>
while (true)
always blocks the page until it finishes using a break
statement, in your code is never finishing, so what you need to do is call the function itself in the timeout (and make i
a global variable to keep track of the array position)
let i = 0;
function changeDynamicText() {
var descriptions = ['list','of','strings','to','loop','over'];
setTimeout(function () {
document.getElementById("dynamicline").innerHTML = descriptions[i];
changeDynamicText()
}, 600);
i = i + 1;
if (i >= descriptions.length) i = 0;
}
loops are blockers infinite loops are infinite blockers. What you need is a time based switcher - a built in timeout functionality which you can call in a cyclical manner - or a, on interval ticker. Any of them will do...
function changeDynamicText() {
var descriptions =
['list','of','strings','to','loop','over'];
var i = 0;
setInterval( tick, 800 );
function tick( ) {
dynamicline.innerHTML = descriptions[ i++ ];
if(i >= descriptions.length-1 ) i = 0
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="about.css">
<meta charset="UTF-8">
<title>My Site</title>
</head>
<script>
</script>
<body onload="changeDynamicText()">
<p id="dynamicline">Starting Text</p>
</body>
</html>