A
You don't need a promise, even if you can:Why do I think there's no need for a promis in this case, because the envelope of the promise here doesn't do any useful work... I mean, the promis wrapper doesn't hurt much in any case, but this particular task is well managed without such a charge:generateElements();
const $cells = document.querySelectorAll('.cell');
const $startButton = document.getElementById('start');
$startButton.addEventListener('click', () => {
$cells.forEach((cell, idx) => setTimeout(() => {
cell.classList.add('cell__anim');
}, 100 * idx));
}, { once: true });
function generateElements() {
document.body.insertAdjacentHTML('beforeend',
<section> ${Array.from({ length: 50 }, (_, i) => <div class="cell">${i + 1}</div>).join('')} </section>
);
}section { display: flex; flex-wrap: wrap; margin: 1rem 0 0; padding: 1px; }
.cell { flex: 0 0 1.2em; line-height: 1.2; margin: -1px 0 0 -1px; padding: 0.5em; text-align: center; border: 1px solid #ccc; transition: background-color 0.3s ease; }
.cell.cell__anim { background-color: #ded; }<button id="start">Start</button>It simply sets a separate time frame for each element, with a steady increase in the delay.Here's one. setIntervalHmm:generateElements();
const $cells = document.querySelectorAll('.cell');
const $startButton = document.getElementById('start');
$startButton.addEventListener('click', () => {
let curIdx = -1;
const interval = setInterval(() => {
const cell = $cells[++curIdx];
if (!cell) return void(clearInterval(interval));
cell.classList.add('cell__anim');
}, 100);
}, { once: true });
function generateElements() {
document.body.insertAdjacentHTML('beforeend',
<section> ${Array.from({ length: 50 }, (_, i) => <div class="cell">${i + 1}</div>).join('')} </section>
);
}section { display: flex; flex-wrap: wrap; margin: 1rem 0 0; padding: 1px; }
.cell { flex: 0 0 1.2em; line-height: 1.2; margin: -1px 0 0 -1px; padding: 0.5em; text-align: center; border: 1px solid #ccc; transition: background-color 0.3s ease; }
.cell.cell__anim { background-color: #ded; }<button id="start">Start</button>On each teration, the index of the element in the collections is steadily increased (until we go outside its borders) and add the class to the current index element.Both uses the method querySelectorAllwhich returns the collection of elements in order to follow them in the document.Optical use once Method addEventListener It's just to be simplified - the listener will be automatically removed after the first event (i.e., this option does not need to be removed by the listener or to use the variable-flagged flags "he's already started."Bonus solution is a promis option that is considered the only justification in this case:generateElements();
const $cells = document.querySelectorAll('.cell');
const $startButton = document.getElementById('start');
const sleep = delay => new Promise(resolve => setTimeout(resolve, delay));
$startButton.addEventListener('click', async () => {
for (const cell of $cells) {
cell.classList.add('cell__anim');
await sleep(100);
}
}, { once: true });
function generateElements() {
document.body.insertAdjacentHTML('beforeend',
<section> ${Array.from({ length: 50 }, (_, i) => <div class="cell">${i + 1}</div>).join('')} </section>
);
}section { display: flex; flex-wrap: wrap; margin: 1rem 0 0; padding: 1px; }
.cell { flex: 0 0 1.2em; line-height: 1.2; margin: -1px 0 0 -1px; padding: 0.5em; text-align: center; border: 1px solid #ccc; transition: background-color 0.3s ease; }
.cell.cell__anim { background-color: #ded; }<button id="start">Start</button>Plus, there's a significant improvement in the readability of the code and a minus in the establishment of extra objects. Whether it's a matter of personal preferences and tasks... I'll use "optional" prosy only when simultaneously Three conditions are met:If sub-objectives are present where the overhead costs are not material (with small heterations);If the charger is sufficiently general, generic (when the project is large and can be reused by a multi-objection code without modifying it);When it's justified by real practical use (not for beauty and not for "timlid, look, I can do the promis, but for the good of the case).