14 подписчиков

Как сделать задержку в цикле for? Pascal, Python, JavaScript

347 прочитали

С этой, казалось бы, очень простой задачей сталкивались все начинающие программисты (также по этой теме: как остановить цикл, как сделать паузу в цикле).

Например, нужно сделать отсчет (прямой или обратный), сделать простенькую пошаговую анимацию, построить график в динамике, чтоб точки добавлялись постепенно и т.д.

В Pascal все просто:

var
i: Integer;

begin
writeln('Старт');
for i := 0 to 5 do
begin
// выполнение кода в цикле
writeln(i);
sleep(1000); // задержка на 1 секунду (задается в мс)
end;
writeln('Цикл завершен');
end.

С этой, казалось бы, очень простой задачей сталкивались все начинающие программисты (также по этой теме: как остановить цикл, как сделать паузу в цикле).

В Python все еще короче (как обычно, за что мы его и любим):

import time
print("Старт")
for i in range(5):
print(i)
time.sleep(1)
print("Цикл завершен")

С этой, казалось бы, очень простой задачей сталкивались все начинающие программисты (также по этой теме: как остановить цикл, как сделать паузу в цикле).-2

А вот с JavaScript все будет поинтереснее. Делаем все то же самое, пока без задержки:

console.log("Старт");
for (let i = 0; i <= 5; i++) {
console.log(i);
}
console.log("Цикл завершен!");
}

Запускам и видим что все работает прекрасно, читаем про задержку, выясняем, что функции задержки в одну строчку в JS нет, вместо этого есть функции setTimeout() и setInterval(). Разница между ними в том, что setTimeout выполняет код внутри нее один раз, а setInterval будет запускать постоянно с заданным промежутком времени, пока не будет сброшен (т.е. цикл здесь как бы уже и не нужен).

Понятней не стало, значит, надо попробовать. Берем функцию setTimeout (нам не нужно многократное повторение, за это у нас отвечает цикл). Помещаем ее внутрь цикла, а уже внутри нее будет тот код, который мы хотим выполнять с задержкой:

console.log("Старт");
for (let i = 0; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000 * i); // задержка увеличивается на 1000 миллисекунд при каждой итерации цикла
}
console.log("Цикл завершен!");

запускаем и здесь нас ждет сюрприз - задержка работает правильно, но сообщения "Старт" и "Цикл завершен" появляются сразу, а уже затем начинается отсчет. Дело в том, что setTimeout в JS не блокирует цикл, программа продолжает выполняться, не дожидаясь его окончания, что мы и видим (это называется асинхронным выполнением).

С этой, казалось бы, очень простой задачей сталкивались все начинающие программисты (также по этой теме: как остановить цикл, как сделать паузу в цикле).-3

А что же делать? Решение заключается в грамотном использовании асинхронных функций и объектов, называемых промизами. Они позволяют указывать, когда функции ждать, а когда выполняться. Не будем углубляться в теорию, просто сделаем рабочий пример:

function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

async function PromiseTimeOut() {
console.log("Старт");
for (let i = 0; i <= 5; i++) {
console.log(i);
await delay(1000); // ждем одну секунду перед выполнением следующей итерации цикла
}
console.log("Цикл завершен!");
}

Здесь нам придется использовать дополнительную функцию delay, а вот она уже и "тормозит" цикл, аналогично предыдущим примерам на Pascal и Python.

Задержка внутри цикла for в JavaScript с использованием async и promise
Задержка внутри цикла for в JavaScript с использованием async и promise

Рабочий код, как обычно, можно посмотреть здесь.

Можно ли такую задержку использовать где угодно, аналогично sleep() в Pascal и Python?

Конечно, вот пример:

создадим свою функцию (даже назовем ее так же) sleep(milliseconds), задержку будем передавать ей в миллисекундах, после этого можно вызывать ее хоть в циклах, хоть в других функциях:

function sleep(ms)
{
return new Promise(resolve => setTimeout(resolve, ms));
}

// Теперь можно ее использовать:
async function F()
{
console.log("Привет");
await sleep(2000); //Ждем 2 секунды
for (let i = 0; i <= 5; i++) {
console.log(i); //Выводим значение i в консоль
await sleep(1000); //Ждем 1 секунду при каждом шаге цикла
}
await sleep(2000); //Снова ждем 2 секунды
console.log("мир");
}

F(); //вызываем функцию F

Только не забывайте async перед объявлением функции, внутри которой будет задержка и не забывайте await перед нашей функцией sleep();

Теперь при вызове наша функция F() выведет "Привет", подождет 2 секунды, затем выведет отсчет от 0 до 5 с задержкой в 1 секунду между числами, потом подождет еще 2 секунды и выведет "мир".

Ну и конечно же, в будущем стоит обратить внимание на запрет повторных нажатий кнопки, узнать, как поставить цикл на паузу и остановить его, применить это все для создания простой анимации и т.д. Если интересно - с удовольствием отвечу в комментариях.

Удачи!

Еще по этой теме: как остановить цикл, как сделать паузу в цикле.