Бесконечная замена фона у массива блоков в рандомное время

Моя задача состоит в том, что бы при старте страницы у массива блоков в случайное время в диапазоне 5 секунд менять фон на случайный из заранее созданного массива. У меня будет примерно 20 таких блоков, я не могу понять как такое провернуть не забивая стек. Прошу помощи

let rhombus = Array.from(document.querySelectorAll('.cont__item'));
    
let colorBg = ['red','purple','lightseagreen'];
    function autoNext() {
        eachBg(rhombus);
        setTimeout(autoNext, 10000); 
    }
    function eachBg(array) {
        array.forEach(element => {
            randomBg(element);
        });
    };
    function randomBg(element) {
        let randomId = randomInteger(0, 3);
        let randomNum = randomInteger(1, 5) * 1000;
        setTimeout(function(){
            element.style.backgroundColor = colorBg[randomId];
            console.log(element)
        }, randomNum);
    };

    function randomInteger(min, max) {
        let rand = min + Math.random() * (max + 1 - min);
        return Math.floor(rand);
    };
    
    setTimeout(autoNext, 2000);
.b-cont {
        display: flex;
        flex-wrap: wrap;
    }
    .b-cont .cont__item {
        width: 50px;
        height: 50px;
        margin: 5px;
        background: #000;
        color: #ffffff;
    }
<div class="b-cont">
    <div class="cont__item">
        &nbsp;
    </div>
    <div class="cont__item">
        &nbsp;
    </div>
    <div class="cont__item">
        &nbsp;
    </div>
    <div class="cont__item">
        &nbsp;
    </div>
    <div class="cont__item">
        &nbsp;
    </div>
</div>


Ответы (2 шт):

Автор решения: novvember

Попробовал сделать такое через классы: для каждого элемента создается свой экземпляр, который и запускается.

Так же, как у вас, задержку задавал через вложенный setTimeout (вместо setInterval), как написано здесь: https://learn.javascript.ru/settimeout-setinterval

class ColoredBlock {
  constructor({element, maxTimeout, colors}) {
    this._element = element;
    this._maxTimeout = maxTimeout;
    this._colors = colors;
  }
  
  _runInterval = () => {
    this._setRandomColor();
    this._timer = setTimeout(this._runInterval, this._getRandomTimeout());
  }
  
  start() {
    this._timer = setTimeout(this._runInterval, this._getRandomTimeout());
  }
  
  stop() {
    clearTimeout(this._timer);
  }
  
  _getRandomTimeout() {
    return Math.random() * this._maxTimeout;
  }
  
  _getRandomColor() {
    const randomInt = Math.floor(Math.random() * this._colors.length);
    return this._colors[randomInt];
  }
  
  _setRandomColor() {
    this._element.style.backgroundColor = this._getRandomColor();
  }
}

const maxTimeout = 5000;
const colors = ['red','purple','lightseagreen'];
const blocks = document.querySelectorAll('.cont__item');

blocks.forEach(blockElement => {
  const block = new ColoredBlock({element: blockElement, maxTimeout, colors});
  block.start();
});
.b-cont {
        display: flex;
        flex-wrap: wrap;
    }
    .b-cont .cont__item {
        width: 50px;
        height: 50px;
        margin: 5px;
        background: #000;
        color: #ffffff;
    }
<div class="b-cont">
    <div class="cont__item">
        &nbsp;
    </div>
    <div class="cont__item">
        &nbsp;
    </div>
    <div class="cont__item">
        &nbsp;
    </div>
    <div class="cont__item">
        &nbsp;
    </div>
    <div class="cont__item">
        &nbsp;
    </div>
</div>

→ Ссылка
Автор решения: Laukhin Andrey

Я не сразу обратил внимание, что Вы хотите у каждого блока индивидуальный таймер.
Вот мой вариант:

const blocks = [...document.querySelectorAll('.block')];
const colors = ['red', 'purple', 'lightseagreen', 'green', 'orange'];
const getRndTime = (max) => Math.random() * max;
const getRndColor = () => colors[~~(Math.random() * colors.length)];

const update = (e) => {
  e.style.background = getRndColor();
  setTimeout(update, getRndTime(5000), e);
}

(function start() {
  blocks.map(e => update(e));
})();
.container {
  display: flex;
  flex-wrap: wrap;
}

.block {
  height: 60px;
  flex: 1 1 20%;
}
<div class="container">
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
</div>

Хочу обратить ваше внимание, что статистически нет особой разницы между одновременной работой N таймеров, и работой одного с временным диапазоном в N раз меньше, который меняет цвет случайного элемента.

Сравните результат:

const blocks = [...document.querySelectorAll('.block')];
const colors = ['red', 'purple', 'lightseagreen', 'green', 'orange'];
const getRndTime = (max) => Math.random() * max;
const getRndBlock = () => blocks[~~(Math.random() * blocks.length)];
const getRndColor = () => colors[~~(Math.random() * colors.length)];


const update = () => {
  getRndBlock().style.background = getRndColor();
  setTimeout(update, getRndTime(5000 / 15));
}

(function start() {
  blocks.map(e => e.style.background = getRndColor());
  update();
})();
.container {
  display: flex;
  flex-wrap: wrap;
}

.block {
  height: 60px;
  flex: 1 1 20%;
}
<div class="container">
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
  <div class="block"></div>
</div>

→ Ссылка