Text use textContent
When assign content to an element use textContent
rather than innerHTML
This prevent a page reflow and all the other overheads associated with new elements.
setTimeout
for better control
Use setTimeout
rather than setInterval
. It lets you start immediately and it also lets you control the display time based on the content. eg use word count to set display time.
For example
const interval = 500; // in ms per word
myTimedFunction(); // starts the timed function immediately.
function myTimedFunction(){
// do something
var wordCount = getWordCount(quote); // imagined function
setTimeout(myTimedFunction, interval * wordCount);
}
Content where it belongs
First... You don't need to manually allocate items to an array.
You had something like
const arr = [];
arr[0] = "blah";
arr[1] = "blah";
arr[2] = "de blah";
arr[3] = "blah";
Which can be done as
const arr = [;
"blah",
"blah",
"de blah",
"blah",
];
However the quotes would be better stored hidden on the page, as it is content not data.
<!-- HTML -->
<ul class="quotes--quotes-hidden">
<li>Blah</li>
<li>Blah</li>
<li>De Blah</li>
<li>Blah</li>
</ul>
/*CSS*/
.quotes--quotes-hidden { display : none; }
And then you can extract it and add it randomly to the display element.
const interval = 15000;
const displayEl = document.getElementById("quotes");
const quotes = [...document.querySelectior(".quotes--quotes-hidden").children];
randomQuote();
function randomQuote() {
// NOTE (val | 0) is the same as Math.floor(val)
displayEl.textContent = quotes[Math.random() * quotes.length | 0].textContent;
setTimeout(randomQuote, interval);
}
Don't repeat random items.
Random can seam very none random to humans. For a small list of items the odds of the same item being repeated is 1/n where n is the number of items. So for 10 items, on average 1 in every ten users will have to wait 30 seconds before they see an new quote, 1 in 100 will wait 45, and 1 in a 1000 will wait 60. Also 1 in ten will see the first quote repeated after the second quote has been displayed.
To avoid repeating the same content use a second array to store upcoming quotes. Each time one is displayed remove it from the array. When the array is empty fill it again and then you start the repeat.
For example
const interval = 15000;
const displayEl = document.getElementById("quotes");
const quotes = [...document.querySelectior(".quotes--quotes-hidden").children];
const quotesPending = [];
randomQuote();
function randomQuote() {
if (quotesPending.length === 0) { // get next round
quotesPending.push(...quotes);
}
const next = quotes.splice(Math.random() * quotes.length | 0)[0];
displayEl.textContent = next.textContent;
setTimeout(randomQuote, interval);
}
This will still let in the occasional repeat. To stop repeats you randomly shuffle the array then random remove one of the first half, display it and push it to the end of the array. This will ensure that a min of n/2 (where n is number items) quotes will be displayed before there is a repeat.
Here are three utility functions for no repeat random selection of a fixed set of items. As compact form, I can not be bothered expanding them and would be used as follows.
// quotes is the array of random quotes
// do once at start
randShuffle(quotes); // randomizes the array
// need mid point
const quotedSizeHalf = quotes.length / 2;
// Do each time you want a new quote
const noRepeatRandQuote = randPlay(quotes, quotedSizeHalf);
The trade of is that you slightly increase the chance of a sequence. The distribution remains flat
// The required functions.
const randI = r => Math.random() * r | 0;
const randShuffle = (a, l = a.length) => { while (l) { a.push(a.splice(randI(l--), 1)[0]) } return a }
const randPlay = (a, r, i = a.splice(randI(r), 1)[0]) => (a.push(i), i);