Jak dynamicznie zmieniać czas interwału w pętli For według numeru indeksu / iteracji?

12

Ponieważ nie mogłem skomentować, jestem zmuszony napisać ten post. Otrzymałem poniższy kod, który opóźnia / czeka dokładnie 1 sekundę lub 1000 milisekund -

let n = 5;
for (let i=1; i<n; i++)
{
  setTimeout( function timer()
  {
      console.log("hello world");
  }, i*1000 );
}

Ale jak mogę to opóźnić i * 1000 sekund zamiast ustalonych 1000 milisekund, aby oczekiwanie zależało od liczby iteracji?

Na przykład, jeśli n = 5, chcę opóźnienie pętli o 1 sekundę w 1. iteracji. 2 sekundy w drugiej iteracji itd. Końcowe opóźnienie wyniesie 5 sekund.

Mikrofon
źródło
2
Więc chcesz zrobić 9 timerów? Jeśli tak, to Twój kod zrobi to, o co prosisz. Nie czeka dokładnie 3 sekundy. W rzeczywistości liczniki nigdy nie będą dokładne.
Scott Marcus,
1
twoje pytanie nie ma sensu
DanStarns
2
Właśnie wypróbowałem swój kod w codepen: codepen.io/Connum/pen/BaaBMwW Dostajesz 9 wiadomości w odstępie 3000 ms - jeśli nie tego chcesz (ale z twojego pytania brzmi to tak, jak jest), proszę określić, jaki masz zamierzony wynik jest.
Constantin Groß
1
Nie wydaje się, aby zrozumieć, jak setTimeout działa na pierwszym miejscu - to nie jest „opóźnienie”. W tej chwili otrzymujesz powiadomienia w 3-sekundowych odstępach, ponieważ już pomnożyłeś 3000 z i- jeśli tego nie zrobiłeś, to dostaniesz wszystkie te powiadomienia w tym samym czasie.
04FS
3
Edycja pytania w celu pogrubienia ostatniego zdania tak naprawdę nie pomaga twojej sprawie. Wielu komentatorów poinformowało Cię, że Twój kod już robi to, o co prosisz (a raczej nie jest całkiem jasne, o co W rzeczywistości prosisz, jeśli nie jest to zamierzony rezultat).
Constantin Groß

Odpowiedzi:

6

Oto funkcja, która wyświetli się natychmiast, a następnie 1 sekundę później, 2 sekundy później, 3 sekundy później itd. Bez specjalnej matematyki, bez obietnic

const n = 5;
let cnt=0;

function show() {
  console.log("call "+cnt,"delay: ",cnt,"sec");
  cnt++;
  if (cnt > n) return; // we are done
  setTimeout(show, cnt*1000 ); // cnt seconds later
}
show()

mplungjan
źródło
1
Bardzo mi przykro, że przegapiłem twoją odpowiedź, było tak wiele komentarzy, nieporozumień, odpowiedzi ... w każdym razie wybieram twoją odpowiedź, ponieważ byłeś pierwszym, który rozwiązał to, o co prosiłem, dziękuję za poświęcony czas.
Mike
@Mike Lol. Inne rozwiązania są użyteczne same w sobie, więc dzięki za akceptację
mplungjan
Pavan's jest taki sam w składni ES6. Trudniej czytać, ale w rzeczywistości jest taki sam. Jego edycja, aby tak się stało, została wykonana w tym samym czasie, kiedy napisałem mój :)
mplungjan
8

Chociaż to zadanie można rozwiązać za pomocą obietnic, reaktywnych strumieni i innych fajnych narzędzi (hej, nikt jeszcze nie sugerował użycia pracowników!), Można je również rozwiązać za pomocą niewielkiej arytmetyki.

Chcesz więc limitów czasu w sekwencji: 1 s, poprzedni + 2 s, poprzedni + 3 i tak dalej. Ta sekwencja to: 1, 3, 6, 10, 15 ... a jej wzór to a[n] = n * (n + 1) / 2. Wiedząc to...

let n = 6;
console.log(new Date().getSeconds());

for (let i = 1; i < n; i++) {
  setTimeout(function timer() {
    console.log(new Date().getSeconds());
  }, 1000 * i * (i + 1) / 2);
}

mbojko
źródło
Matematycy wciąż żyją !! :)
Bilal Siddiqui
5

Możesz spróbować użyć kodu async / await (Promises), aby serializować kod:

const waitSeconds = seconds => new Promise(resolve => setTimeout(resolve, seconds))

async function main () {
 let oldDate = new Date()
 let newDate
 
 /* 
  * If you put 'await' inside the loop you can synchronize the async code, and simulate
  * a sleep function
  */
 for (let i=1; i<5; i++) {
    await waitSeconds(i*1000)
    newDate = new Date()   
    console.log(`Loop for i=${i}, elapsed=${moment(newDate).diff(oldDate, 'seconds')} seconds`)
    oldDate = newDate
 }
 
 console.log('End')
}

main()
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

Mauro Stepanoski
źródło
5

Zajęło mi trochę czasu, aby rozszyfrować twoje pytanie xD, ale czy tego właśnie chcesz?

Spowoduje to ciągłe odpalanie pliku console.log z opóźnieniem i * 1000. więc za pierwszym razem będzie to 1 sekunda (1 * 1000), następnie będzie to 2 sekundy i tak dalej.

let i = 0;
loop = () => {
  setTimeout(() => {
    console.log(new Date()); // for clarity
    i++;
    if (i < 10) {
      loop();
    }
  }, i * 1000)
};
loop();

Pavan Skipo
źródło
Na przykład, jeśli n = 5, chcę opóźnienie pętli o 1 sekundę w 1. iteracji. 2 sekundy w drugiej iteracji itd. Końcowe opóźnienie wyniesie 5 sekund.
Mike
tak, opóźni to 1 sekundę na 1. iterację, 2 sekundy na 2. i tak dalej, spróbuj
Pavan Skipo
Twój opis nie pasuje do kodu. Ale to działa
mplungjan,
3

Pętla nie czeka na zakończenie funkcji limitu czasu. Tak więc, gdy pętla działa, planuje alert dla każdego indeksu.

Możesz użyć funkcji, która będzie działać zgodnie z twoim indeksem, ale zaplanowanym w tym samym czasie. Możesz poczuć różnicę 3 sekund.

function test(i){
    setTimeout( function timer(){
        console.log("hello world" + i);
    }, i*3000);
}
for (let i=1; i<4; i++) {
   test(i);
}
Bilal Siddiqui
źródło
3

Użyj wywołań rekurencyjnych zamiast pętli for

let i=1;
function a(i) {
  if (i > 5)
    return
  else
    b("message", i)
}

function b(s, f) {
  setTimeout(function timer() {
    console.log(s + " " + f + " seconds");
  }, f * 1000);
  a(++i);
}
a(i);

elipsa
źródło
Na przykład, jeśli n = 5, chcę opóźnienie pętli o 1 sekundę w 1. iteracji. 2 sekundy w drugiej iteracji itd. Końcowe opóźnienie wyniesie 5 sekund.
Mike