Witam. Jak zrobić pętle która będzie odliczała od 0 do 100 ale że cyfry będą się powiększać co sekunde. Myśle że może dałoby to rade zrobić setTimeout albo async await ale jak ?
Np tak:
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms))
const count = async () => {
for (let i = 0; i < 100; i++) {
console.log(i) // you can change this to whatever
await delay(1000)
}
}
count()
Do takiego prostego zastosowania wystarczy pod setTimeout
podstawić liczbę milisekund pomnożoną przez liczbę w pętli.
for (let i = 0; i <= 100; i++) {
setTimeout(() => {
console.log(i);
}, 1000 * i);
}
Różnie można do tego podejść. Np. można zrobić funkcję, która za każdym uruchomieniem zwiększa licznik i jeśli licznik jest mniejszy od danej liczby, to wywołuje setTimeout z odpowiednim opóźnieniem:
let c = 0;
(function foo() {
console.log(c);
if (++c <= 100) setTimeout(foo, 1000);
})();
Ale jeśli masz więcej takich rzeczy do zrobienia, to wtedy wygodniej użyć async/await (przy takim małym kawałku kodu to nie ma znaczenia, ale przy większych rzeczach rozwiązania oparte na zwykłych callbackach będą po prostu nieczytelne).
Może po prostu setInterval
z 1000ms zamiast setTimeout
i w odpowiednim momencie wyczyścić timer, żeby nie liczył w nieskończoność. Prostsze rozwiązanie, mniej próbowania zrobienia na siłę setInterval
z setTimeout
.
@Aisekai: Pomijając już samą potrzebę czyszczenia interwałów - setTimeout
w pętli / rekursywny i setIntervel
to nie jest dokładny zamiennik. setIterval
scheduluje wywołania na konkretny czas, setInterval
umożliwia stałe odstępy czasowe pomiędzy wywołaniami, niezależnie od tego ile czasu zajmują operacje w pojedynczym cyklu.
Przykład:
const timeExpensiveOperation = () => {
return new Array(1e6).fill(0).map((_, i) => i ** 2);
};
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const count1 = async () => {
return new Promise((resolve) => {
let counter = 0;
let start = performance.now();
const handle = setInterval(() => {
const timeBetween = performance.now() - start;
timeExpensiveOperation();
counter++;
console.log(counter, `Time between (setInterval 100): ${timeBetween.toFixed(2)} ms`);
if (counter === 10) {
clearInterval(handle);
resolve();
}
start = performance.now();
}, 100);
});
};
const count2 = async () => {
let counter = 0;
let start = performance.now();
while (counter < 10) {
await delay(100);
const timeBetween = performance.now() - start;
timeExpensiveOperation();
counter++;
console.log(counter, `Time between (setTimeout 100): ${timeBetween.toFixed(2)} ms`);
start = performance.now();
}
};
const main = async () => {
console.log('\nsetInterval:')
await count1();
console.log('\nsetTimeout:')
await count2();
};
main();
Wyniki będą bardzo różne:
setInterval:
1 "Time between (setInterval 100): 100.30 ms"
2 "Time between (setInterval 100): 13.80 ms"
3 "Time between (setInterval 100): 23.40 ms"
4 "Time between (setInterval 100): 26.80 ms"
5 "Time between (setInterval 100): 0.80 ms"
6 "Time between (setInterval 100): 6.30 ms"
7 "Time between (setInterval 100): 0.10 ms"
8 "Time between (setInterval 100): 27.60 ms"
9 "Time between (setInterval 100): 19.60 ms"
10 "Time between (setInterval 100): 20.10 ms"
setTimeout:
1 "Time between (setTimeout 100): 100.40 ms"
2 "Time between (setTimeout 100): 100.30 ms"
3 "Time between (setTimeout 100): 100.20 ms"
4 "Time between (setTimeout 100): 100.20 ms"
5 "Time between (setTimeout 100): 100.70 ms"
6 "Time between (setTimeout 100): 100.30 ms"
7 "Time between (setTimeout 100): 100.30 ms"
8 "Time between (setTimeout 100): 100.20 ms"
9 "Time between (setTimeout 100): 100.30 ms"
10 "Time between (setTimeout 100): 100.40 ms"
Często zależy nam na tym drugim zachowaniu, co mój przykład uwzględnia. Za pomocą setTimeout
da się zasymulować setInterval
(zabacz przykład @Xarviel), ale w drugą stronę to już nie bardzo.
Oczywiście w przypadku OP nie ma to znaczenia - oba zadziałają niemal identycznie, uzasadniam tylko, czemu odruchowo użyłem setTimeout
.