Если вы только что прочитали этот заголовок и сказали: «Чувак, к черту этого парня. Я знаю, как использовать чертов setTimeout», эта статья не для вас, (или вы 💩-мешок, который ненавидит знать вещи). Идея написать это возникла, когда я увидел, как этот метод злоупотребляют младшими/новыми разработчиками, и я понял, что не так много указаний относительно того, как, когда и почему его использовать.

Что происходит, когда вы вызываете setTimeout?

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

Когда вы вызываете setTimeout, он отправляет вашу функцию в WebAPI, который затем ожидает указанной задержки, чтобы поместить вашу функцию в очередь. Как только в стеке вызовов появляется место, цикл событий помещает вашу функцию в стек для вызова.

Возможно, вы видели, как люди вызывают setTimeout следующим образом:

setTimeout(()=> {/* some code to execute */}, 0);

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

Каковы некоторые разумные варианты использования setTimeout?

  • Чтобы установить минимальную задержку перед выполнением функции
  • Удалить блокирующую функцию из стека вызовов (если вы не можете использовать веб-воркер)
  • Как быстрый макет для асинхронной операции

Установите минимальную задержку перед выполнением функции

setTimeout(delayedFunction, 2000);

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

Это обычно используется для анимации. Это нормально, но по мере того, как API веб-анимации становится более зрелым, вариантов использования setTimeout будет меньше. Кроме того, многие анимации могут быть обработаны с помощью анимации CSS с ускорением графического процессора.

Удалить блокировку выполнения из стека вызовов

setTimeout(someHeavyFunction);

setTimeout может быть быстрым и простым решением для предотвращения блокировки стека вызовов долго выполняющимися функциями. Однако это не должно быть постоянным решением; вместо этого лучше использовать что-то вроде веб-работника. У них довольно широкая поддержка, если вам не нужно поддерживать старые версии Internet Explorer.

Перед использованием setTimeout убедитесь, что функция оптимизирована. Очевидно, что некоторые операции могут быть сложными и тяжелыми, несмотря ни на что, но разбиение большой функции на более мелкие сегменты и снижение нагрузки на браузер может устранить необходимость использования setTimeout. Это также дает дополнительное преимущество, делая ваш код более кратким и организованным.

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

«Тебе лучше проверить себя, прежде чем разрушить себя»

- Кубик льда

Моделирование асинхронности

const randomDelay = (maxDelay = 2000) => 
     Math.floor(Math.random() * maxDelay);
setTimeout(sendResponse, randomDelay());

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

Что плохого в использовании setTimeout?

Категорически запрещается использовать setTimeout для исправления состояния гонки (или ошибки «данные не готовы» для тех педантичных читателей, которым не нравится использование термина состояние гонки в одном сообщении). многопоточный язык, такой как JavaScript). Я слишком часто вижу это среди новых разработчиков (а иногда и среди не очень новых разработчиков, эй).

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

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

Другое решение, такое как использование промиса или асинхронной функции, может быть лучшим. Подождите, пока обещание/асинхронность разрешится и отправит событие, чтобы ваши функции знали, что данные готовы. Это будет:

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

TLDR;

setTimeout — отличный метод в JavaScript, и ему определенно есть место в языке, но, несмотря ни на что, его можно использовать как во благо, так и во зло.

  • Знайте, как это работает
  • Используйте его, когда вам это нужно, и это имеет смысл
  • Не используйте его, чтобы скрыть более серьезные проблемы