Как динамически изменить интервал времени в цикле For в соответствии с индексом / номером итерации?

12

Поскольку я не мог комментировать, я вынужден написать этот пост. Я получил следующий код, который задерживает / ждет ровно 1 секунду или 1000 миллисекунд -

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

Но как я могу отложить это на 1000 секунд вместо фиксированных 1000 миллисекунд, чтобы ожидание зависело от номера итерации?

Например, если n = 5, то я хочу, чтобы задержка цикла составляла 1 секунду в 1-й итерации. 2 секунды во второй итерации и т. Д. Окончательная задержка составит 5 секунд.

Майк
источник
2
Итак, вы хотите сделать 9 таймеров? Если это так, то ваш код будет делать то, что вы просите. Это не ждет ровно 3 секунды. На самом деле таймеры никогда не будут точными.
Скотт Маркус
1
ваш вопрос не имеет смысла
DanStarns
2
Только что опробовал свой код в коде ручки: codepen.io/Connum/pen/BaaBMwW Вы получаете 9 сообщений с разницей в 3000 мс - если это не то, что вы хотите (но из вашего вопроса это звучит так, как есть), пожалуйста, укажите, каков ваш ожидаемый результат является.
Константин Грос
1
Вы, кажется, не понимаете, как setTimeout работает в первую очередь - это не «задержка». Прямо сейчас вы получаете ваши оповещения с интервалом в 3 секунды, потому что вы уже умножили 3000 на i- если вы этого не сделаете, то вы получите все эти оповещения одновременно .
04FS
3
Редактирование вопроса для того, чтобы сделать ваше последнее предложение жирным, не очень помогает вашему делу. Несколько комментаторов сказали вам, что ваш код уже выполняет то, что вы просите (или, скорее, не совсем понятно, о чем вы на самом деле просите, если это не ваш ожидаемый результат).
Константин Грос

Ответы:

6

Вот функция, которая будет отображаться немедленно, затем через 1 секунду, через 2 секунды после, через 3 секунды после этого и т. Д. Никакой специальной математики, никаких обещаний не требуется

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
источник
1
Мне очень жаль, что я пропустил ваш ответ, было так много комментариев, недоразумений, ответов ... в любом случае, я выбираю ваш ответ, так как вы были первым, кто решил, что я спросил, спасибо за ваше время, сэр.
Майк
@ Майк Лол. Другие решения полезны сами по себе, так что спасибо за принятие
mplungjan
У Павана тот же синтаксис ES6. Труднее читать, но на самом деле это то же самое. Его править , чтобы сделать это так было сделано в то же время , как я писал мой :)
mplungjan
8

Хотя эту задачу можно решить с помощью обещаний, реактивных потоков и других интересных инструментов (эй, никто еще не предлагал использовать рабочих!), Ее также можно решить с помощью небольшой арифметики.

Таким образом, вы хотите тайм-ауты в последовательности: 1 с, предыдущий + 2 с, предыдущий + 3 с и так далее. Эта последовательность: 1, 3, 6, 10, 15 ... и ее формула a[n] = n * (n + 1) / 2. Знаю это...

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
источник
Математики еще живы !! :)
Билал Сиддики
5

Вы можете попробовать использовать async / await (Promises) для сериализации вашего кода:

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>

Мауро Степаноски
источник
5

Мне понадобилось время, чтобы расшифровать твой вопрос xD, но ты этого хочешь?

Это будет продолжать запускать console.log с задержкой i * 1000 каждый раз. поэтому в первый раз это будет 1 секунда (1 * 1000), затем это будет 2 секунды и так далее.

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

Паван Скипо
источник
Например, если n = 5, то я хочу, чтобы задержка цикла составляла 1 секунду в 1-й итерации. 2 секунды во второй итерации и т. Д. Окончательная задержка составит 5 секунд.
Майк
да, это задержит 1 секунду для 1-й итерации, 2 секунды для 2-й и т. д., попробуйте
Pavan Skipo
Ваше описание не соответствует коду. Но это делает работу
mplungjan
3

Цикл не ожидает завершения функции тайм-аута. Таким образом, когда цикл запускается, он планирует ваше оповещение для каждого индекса.

Вы можете использовать функцию, которая будет работать в соответствии с вашим индексом, но по расписанию одновременно. Вы можете почувствовать разницу в 3 секунды.

function test(i){
    setTimeout( function timer(){
        console.log("hello world" + i);
    }, i*3000);
}
for (let i=1; i<4; i++) {
   test(i);
}
Билал Сиддики
источник
3

Используйте рекурсивные вызовы вместо цикла 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);

эллипсис
источник
Например, если n = 5, то я хочу, чтобы задержка цикла составляла 1 секунду в 1-й итерации. 2 секунды во второй итерации и т. Д. Окончательная задержка составит 5 секунд.
Майк