@Nikonorovich

Как работают циклы с таймаутом?

Заинтересовала задачка которую получил на собеседовании
есть первый цикл
let i = 0;
       for (i = 0; i < 5; i++) {
        setTimeout(() =>  console.log(i), 1000);
      }

выводит на экран 5 5 5 5 5
И другой цикл
for (let i = 0; i < 5; i++) {
        setTimeout(() =>  console.log(i), 1000);
      }

выводит 0 1 2 3 4
Можете объяснить, почему срабатывает по разному?
  • Вопрос задан
  • 95 просмотров
Решения вопроса 1
bingo347
@bingo347 Куратор тега JavaScript
Ищу Java и TypeScript разработчиков
Первое что нужно понять, таймер работает асинхронно, а значит будет выполнен после цикла.
Второе - let имеет блочную область видимости (переменная видна в том блоке, где была объявлена, при этом первый операнд for считается тем же блоком, что и тело цикла)
Третье - циклы создают новый скоуп на каждую итерацию (на каждой итерации будет свой let i, при условии что этот оператор внутри цикла)

Ну и еще, в Ваших примерах 1000 относится не к таймауту, это просто бесполезная операция, а таймаут получит значение по умолчанию - 0, думаю это не совсем то, что Вы ожидаете.

Еще один важный момент, функциональное выражение (а стрелочная функция - это тоже функциональное выражение) внутри цикла будет создавать по функции на каждой итерации цикла. Это очень плохо и по памяти и по производительности (такие функции еще и компилироваться и оптимизироваться будут раздельно). И если в случае с let внутри цикла функции хотя бы будут отличаться замыканием (каждая замкнет свою i), то в первом случае будет 5 абсолютно идентичных функций.
Тут можно очень хорошо показать себя, если помимо объяснения принципов работы вспомнить, что setTimeout умеет передавать аргументы в свой колбэк:
const f = i => {
  console.log(i);
};
for (let i = 0; i < 5; i++) {
  setTimeout(f, 1000, i);
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@402d
начинал с бейсика на УКНЦ в 1988
в первом случае у тебя одна глобальная переменная i.
повещенные 5 таймеров сработают через секунду и все выведут ее текущее значение.

во втором случае переменных i две. параметр цикла и глобальная.
но тут еще лямбда замыкание.
Я редко пишу на явоскрипт. В других языках проблему решают по разному.
например специальный модификатор final . А гдето как в вашем случае
создается неявная копия переменной, которая уже используется в отложенном событии
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы