Comment modifier dynamiquement le temps d'intervalle dans la boucle For selon le numéro d'index / d'itération?

12

Comme je ne pouvais pas commenter, je suis obligé d'écrire ce post. J'ai obtenu le code ci-dessous qui retarde / attend exactement 1 seconde ou 1000 millisecondes -

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

Mais comment puis-je le retarder de 1 * 1000 secondes au lieu de 1 000 millisecondes fixe, de sorte que l'attente dépend du nombre d'itérations?

Par exemple, si n = 5, alors je veux le délai de boucle 1 seconde dans la 1ère itération. 2 secondes en seconde itération, et ainsi de suite .. le retard final sera de 5 secondes.

Mike
la source
2
Vous voulez donc faire 9 minuteries? Si c'est le cas, votre code fera ce que vous demandez. Il n'attend pas exactement 3 secondes. En fait, les minuteries ne seront jamais exactes.
Scott Marcus
1
votre question n'a aucun sens
DanStarns
2
Vous venez d' essayer votre code dans un codepen: codepen.io/Connum/pen/BaaBMwW Vous obtenez 9 messages à 3000 ms d'intervalle - si ce n'est pas ce que vous voulez (mais à partir de votre question, cela ressemble à ça), veuillez préciser quel est le résultat souhaité est.
Constantin Groß
1
Vous ne semblez pas comprendre comment setTimeout fonctionne en premier lieu - ce n'est pas un «retard». À l'heure actuelle, vous recevez vos alertes à des intervalles de 3 secondes, car vous avez déjà multiplié les 3000 par i- si vous ne le faites pas, vous obtiendrez toutes ces alertes en même temps.
04FS
3
Modifier la question afin de rendre votre dernière phrase en gras n'aide pas vraiment votre cas. Plusieurs commentateurs vous ont maintenant dit que votre code fait déjà ce que vous demandez (ou plutôt, ce n'est pas tout à fait clair ce que vous demandez réellement, si ce n'est pas le résultat souhaité).
Constantin Groß

Réponses:

6

Voici une fonction qui s'affichera immédiatement, puis 1 seconde plus tard, 2 secondes après que, 3 secondes après cela, etc. Aucun calcul spécial, aucune promesse nécessaire

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
la source
1
Je suis extrêmement désolé d'avoir manqué votre réponse, il y a eu tellement de commentaires, de malentendus, de réponses ... de toute façon je choisis votre réponse car vous étiez le premier à avoir résolu ce que j'ai demandé merci pour votre temps monsieur.
Mike
@Mike Lol. Les autres solutions sont utiles en soi, donc merci pour l'acceptation
mplungjan
Pavan est le même dans la syntaxe ES6. Plus difficile à lire mais c'est en fait la même chose. Son montage pour le faire a été fait en même temps que j'ai écrit le mien :)
mplungjan
8

Bien que cette tâche puisse être résolue avec des promesses, des flux réactifs et d'autres outils sympas (hé, personne n'a encore suggéré d'utiliser des travailleurs!), Elle peut également être résolue avec un peu d'arithmétique.

Vous voulez donc des délais d'attente dans une séquence: 1s, le précédent + 2s, le précédent + 3s, et ainsi de suite. Cette séquence est: 1, 3, 6, 10, 15 ... et sa formule est a[n] = n * (n + 1) / 2. Sachant que...

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
la source
Les mathématiciens sont toujours en vie !! :)
Bilal Siddiqui
5

Vous pouvez essayer d'utiliser async / wait (Promises), pour sérialiser votre code:

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
la source
5

Cela m'a pris du temps pour déchiffrer votre question xD, mais est-ce ce que vous voulez?

Cela continuera à tirer console.log avec un retard i * 1000 à chaque fois. donc la première fois ce sera 1 seconde (1 * 1000), ensuite ce sera 2 secondes et ainsi de suite.

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

Pavan Skipo
la source
Par exemple, si n = 5, alors je veux le délai de boucle 1 seconde dans la 1ère itération. 2 secondes en seconde itération, et ainsi de suite .. le retard final sera de 5 secondes.
Mike
yup cela retardera 1 seconde pour la 1ère itération, 2 secondes pour la 2ème et ainsi de suite, essayez-le
Pavan Skipo
Votre description ne correspond pas au code. Mais ça fait l'affaire
mplungjan
3

La boucle n'attend pas la fin de la fonction de temporisation. Ainsi, lorsque la boucle s'exécute, elle planifie votre alerte pour chaque index.

Vous pouvez utiliser une fonction qui s'exécutera en fonction de votre index mais planifiée en même temps. Vous pouvez sentir la différence de 3 secondes.

function test(i){
    setTimeout( function timer(){
        console.log("hello world" + i);
    }, i*3000);
}
for (let i=1; i<4; i++) {
   test(i);
}
Bilal Siddiqui
la source
3

Utiliser des appels récursifs au lieu de la boucle 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);

ellipse
la source
Par exemple, si n = 5, alors je veux le délai de boucle 1 seconde dans la 1ère itération. 2 secondes en seconde itération, et ainsi de suite .. le retard final sera de 5 secondes.
Mike