Problem z setTimeout w pętli

0

Kochani!

Chciałem napisać na szybko prototyp światełek na choinkę :D; https://jsfiddle.net/59n4Lbx2/
Każda ma migać po sobie.
Po każdej pętli następna lampka z prawej ma się zaświecić na niebiesko i tak zostać.
Ku mojemu zdziwieniu co drugie wywołanie pętli nic nie robi.
Czy widzicie gdzie jest problem ?

3

Oj, chyba piszesz coś w stylu enterprise Hello World ;) W sensie mnóstwo funkcji i zawiły flow na coś, co powinno być proste.

  lampList.forEach((lamp, i) => {
    if (checkIfLast(i)) {
      lamp.turnBlue(i * 100 + delay);
      lampList.pop();

jak robisz forEach, to wypadałoby nie zmieniać tablicy. Chociaż tutaj pewnie nic się nie stanie, bo i tak pop() usunie ostatnią wartość, więc po prostu iteracji będzie mniej. Ale jeśli twoim celem jest usunięcie ostatniej lampy z tablicy i wywołanie metody turnBlue, to po co w ogóle robisz to w forEach i na ifie? (i jeszcze niepotrzebnie dodatkową funkcję w stylu enterprise: checkIfLast(id)) Przecież możesz tak:

lampList.pop().turnBlue(lampList.length - 1 * 100 + delay);

czyli zdejmujesz z tablicy ostatni element i wywołujesz jego metodę turnBlue.

Ogólnie ten kod jest tak zamotany, że lepiej przepisać w prostszy sposób, będzie łatwiej zlokalizować błąd.
Np. nie rozumiem, czemu przypisujesz każdemu elementowi id? Przecież możesz utworzyć divy dynamicznie:

function createLamp(id) {
  const place = document.createElement('div');
  document.querySelector('main').appendChild(place);
  return {
    place, // destructuring z ES6
    .....

No i jak masz tablicę tych obiektów utworzonych przez createLamp, to nie potrzebujesz id, bo każdy element będzie miał jakiś indeks. Więc zapamiętujesz po prostu indeks ostatniego zaświeconego elementu (albo tak jak teraz robisz - zdejmujesz po prostu element).

Myślę, że tutaj mogło się coś porypać z tymi id.

Jeszcze na co warto zwrócić uwagę, to timeouty. Czy nie jest np. tak, że równocześnie wywołują się dwa timeouty, gdzie jeden zmienia kolor na czerwony, drugi na niebieski i się anulują. Ale nie wiem, czy tak jest, zgaduję tylko. Ogólnie to tych timeoutów w ogóle nie powinno być, tylko walnąć jeden setInterval, który będzie zapalał i gasił odpowiednie światełka w odpowiednim czasie i tyle (a jak zapali wszystkie, to zrobić clearInterval)

2

W zasadzie nie wiem dlaczego Twoje nie działa, ale nie chciało mi się zagłębiać :)
Ja bym to zrobił tak, co by się nie rozdrabniać to 100 lampek (dodaje dynamicznie javascriptem)
https://jsfiddle.net/263ohn4L/

const lamps = new Map();
const main = document.querySelector('main');

for (let i = 0; i < 100; i += 1) {
    const div = document.createElement('div')
    lamps.set(div, 'brown');
    main.append(div);
}

const sleep = (time) => new Promise((resolve) => window.setTimeout(resolve, time));

async function smallLoop() {
    for (const div of [...lamps.keys()]) {
        const previous = div.previousElementSibling
        const next = div.nextElementSibling;
        if (previous) previous.classList.remove('red');
        if (!next || lamps.get(next) === 'blue') {
    	    div.classList.add('blue');
            lamps.set(div, 'blue');
            break;
        } else {
    	    div.classList.add('red');
        }
        await sleep(30);
    }
}

async function bigLoop() {
    for (let i = 0; i < lamps.size; i += 1) {
  	await smallLoop();
    await sleep(100);
    }
}
bigLoop();

2

Moja wersja: https://jsfiddle.net/j1xm6znu/2/

const numberOfLights = 30;
const timeSpan = 20;

const main = document.querySelector('main');
const lights = [];

for (let i = 0; i < numberOfLights; i++) {
   const light = document.createElement('div');
   main.appendChild(light);     
   lights.push(light);
}

let index = -1;
let light;
(function update() {   
   if (light) light.classList.remove('red');
   index = (index + 1) % lights.length;
   light = lights[index];
   
   if (index == lights.length - 1) {
       lights.pop().classList.add('blue');
   } else { 
       light.classList.add('red');
   }
   
   if (lights.length) setTimeout(update, timeSpan);
})();

2

Jestem pod wrażeniem obu rozwiązań :D

1 użytkowników online, w tym zalogowanych: 0, gości: 1