setTimeout
— это встроенная функция JavaScript (хотя ее можно использовать с библиотекой, такой как jQuery, как мы увидим позже), которая вызывает функцию или выполняет фрагмент кода после указанной задержки (в миллисекундах). Это может быть полезно, например, если вы хотите отобразить всплывающее окно после того, как посетитель просматривает вашу страницу в течение определенного периода времени, или вы хотите небольшую задержку перед удалением эффекта наведения из элемента (в случае, если пользователь случайно муссировали).
Базовый пример setTimeout
Чтобы продемонстрировать концепцию, следующая демонстрация отображает всплывающее окно через две секунды после нажатия кнопки.
Если вы не видите всплывающее окно открытым, посетите CodePen и запустите демо-версию там.
Синтаксис
Из документации MDN синтаксис для setTimeout
выглядит следующим образом:
var timeoutID = scope.setTimeout(function[, delay, param1, param2, ...]); var timeoutID = scope.setTimeout(function[, delay]); var timeoutID = scope.setTimeout(code[, delay]);
где:
-
timeoutID
— это числовой идентификатор, который можно использовать вместе сclearTimeout()
для отмены таймера. -
scope
относится к интерфейсу Window или интерфейсу WorkerGlobalScope . -
function
— это функция, которая будет выполнена после истечения таймера. -
code
(в альтернативном синтаксисе) — это строка кода, которая должна быть выполнена. -
delay
— это количество миллисекунд, на которое должен быть задержан вызов функции. Если опущено, по умолчанию это 0.
Примечание: квадратные скобки []
обозначают необязательные параметры.
setTimeout против window.setTimeout
Вы заметите, что приведенный выше синтаксис использует scope.setTimeout
. Почему это?
Что ж, при запуске кода в браузере scope
будет ссылаться на объект глобального window
. И setTimeout
и window.setTimeout
ссылаются на одну и ту же функцию, с той лишь разницей, что во втором выражении мы setTimeout
метод setTimeout
как свойство объекта window
.
На мой взгляд, это добавляет сложности за небольшую выгоду. Если вы определили альтернативный метод setTimeout
который будет найден и возвращен в приоритете в цепочке областей действия, то у вас, вероятно, возникнут более серьезные проблемы.
Для целей данного руководства я опущу window
, но в конечном итоге какой синтаксис вы выбрали, зависит от вас.
Примеры использования
setTimeout
принимает ссылку на функцию в качестве первого аргумента.
Это может быть имя функции:
function explode(){ alert("Boom!"); } setTimeout(explode, 2000);
Переменная, которая ссылается на функцию:
var explode = function(){ alert("Boom!"); }; setTimeout(explode, 2000);
Или анонимная функция:
setTimeout(function(){ alert("Boom!"); }, 2000);
Также возможно передать setTimeout
строку кода для его выполнения:
setTimeout("alert('Boom!');", 2000);
Это, однако, не рекомендуется по следующим причинам:
- Трудно читать (и, следовательно, трудно поддерживать и / или отлаживать)
- Он использует подразумеваемую
eval()
, которая представляет потенциальную угрозу безопасности - Это медленнее, чем альтернативы, так как он должен вызывать интерпретатор JS.
Этот вопрос StackOverflow предлагает больше информации по вышеуказанным пунктам.
Передача параметров в setTimout
В базовом сценарии предпочтительным кросс-браузерным способом передачи параметров в обратный вызов, выполняемый setTimeout
является использование анонимной функции в качестве первого аргумента.
В следующем примере мы выбираем случайное приветствие из массива greetings
и передаем это случайное приветствие в качестве параметра функции greet
, которая выполняется setTimeout
с задержкой в одну секунду:
function greet(greeting){ console.log(greeting); } function getRandom(arr){ return arr[Math.floor(Math.random()*arr.length)]; } var greetings = ["Hello", "Bonjour", "Guten Tag"], randomGreeting = getRandom(greetings); setTimeout(function(){ greet(randomGreeting); }, 1000);
Альтернативный метод
Как видно из синтаксиса в верхней части статьи , существует второй метод передачи параметров в обратный вызов, выполняемый setTimeout
. Это включает в себя перечисление любых параметров после задержки.
Со ссылкой на наш предыдущий пример это даст нам:
setTimeout(greet, 1000, randomGreeting);
К сожалению, это не работает в IE9 или ниже, где параметры указаны как undefined
. Тем не менее, есть поллифл, доступный на MDN .
Проблема с this
Код, выполняемый setTimeout
, запускается в отдельном контексте выполнения функции, из которой он был вызван. Это проблематично, когда важен контекст this
ключевого слова:
var person = { firstName: "Jim", introduce: function(){ console.log("Hi, I'm " + this.firstName); } }; person.introduce(); // Outputs: Hi, I'm Jim setTimeout(person.introduce, 50); // Outputs: Hi, I'm undefined
Причина этого вывода в том, что в первом примере this
указывает на объект person
, тогда как во втором примере this
указывает на объект глобального window
(у которого нет свойства firstName
).
Чтобы противодействовать этому, существуют различные меры:
Явно установите значение this
Вы можете сделать это, используя bind , метод, который создает новую функцию, которой при вызове присваивается ключевое слово this
с указанным значением (в нашем случае это объект person
). Это даст нам:
setTimeout(person.introduce.bind(person), 50);
Примечание: bind
было введено в ECMAScript 5, поэтому будет работать только в более современных браузерах . Вы можете прочитать больше об этом (и других методах установки значения this
) в этой статье SitePoint .
Используйте библиотеку
Многие библиотеки поставляются со встроенными функциями для решения этой проблемы. Например, метод jQuery.proxy () в jQuery. Это берет функцию и возвращает новую, которая всегда будет иметь определенный контекст. В нашем случае это будет:
setTimeout($.proxy(person.introduce, person), 50);
Использование функций стрелок с setTimeout
Функции стрелок были введены с ES6. У них намного более короткий синтаксис, чем у обычной функции:
(param1, param2, paramN) => expression
Конечно, вы можете использовать их с setTimeout
, но есть один момент, о котором следует знать, а именно, что функции стрелок не имеют своих собственных значений. Вместо этого они используют значение this
лексического контекста.
Используя обычную функцию:
const person = { firstName: "Jim", introduce: function() { console.log(`Hi, I'm ${this.firstName}`); } }; person.introduce(); // Hi, I'm Jim
Используя функцию стрелки:
const person = { firstName: "Jim", introduce: () => { console.log(`Hi, I'm ${this.firstName}`); } }; person.introduce(); // Hi, I'm undefined
Во втором примере this
указывает на объект глобального window
(у которого нет свойства firstName
).
Это может сбить нас с setTimeout
при использовании функций стрелок с setTimeout
. Ранее мы видели, как мы можем предоставить функцию, вызываемую в setTimeout
с правильным значением:
setTimeout(person.introduce.bind(person), 50);
Это не будет работать при использовании функции стрелки в методе introduce
, так как функция стрелки не имеет своего собственного значения this
. Метод по-прежнему будет регистрироваться как undefined
.
Чистый код с функциями стрелок и setTimeout
Однако, поскольку функции стрелок не имеют своих собственных значений, это также может работать в наших интересах.
Код как это …
var person = { firstName: "Jim", delayedIntroduce: function() { setTimeout( function() { console.log("Hi, I'm " + this.firstName); } .bind(this) , 1000); } } person.delayedIntroduce();
… Можно переписать более кратко с помощью функции стрелки:
const person = { firstName: "Jim", delayedIntroduce() { setTimeout( () => { console.log(`Hi, I'm ${this.firstName}`); }, 1000 ); } } person.delayedIntroduce();
Если вы хотите ознакомиться с функциями стрелок, ознакомьтесь с разделом Функции стрелок ES6: толстый и краткий синтаксис в JavaScript .
Отмена таймера
Возвращаемое значение setTimeout
— это числовой идентификатор, который можно использовать для отмены таймера в сочетании с функцией clearTimeout
:
var timer = setTimeout(myFunction, 3000); clearTimeout(timer);
Давайте посмотрим это в действии. В следующем пене, если вы нажмете кнопку « Пуск» , начнется обратный отсчет. Если обратный отсчет завершится, котята получат его. Однако, если вы нажмете кнопку остановки отсчета , таймер будет остановлен и сброшен. (Если вы не видите крутого эффекта, когда обратный отсчет достигает нуля, перезапустите перо, используя кнопку в правом нижнем углу встраивания.)
Завершение
Одним потенциальным предостережением, о котором следует знать, является тот факт, что setTimeout
является асинхронным, поскольку он ставит в очередь ссылку на функцию, которую он получает для запуска после завершения выполнения текущего стека вызовов. Однако он не выполняется одновременно или в отдельном потоке (из-за однопоточной природы JavaScript).
console.log(1); setTimeout(function(){ console.log(2); }, 0); console.log(3); // Outputs: 1, 3, 2
Существует также некоторая путаница между использованием встроенной функции JavaScript setTimeout
и метода задержки jQuery .
Метод delay
предназначен специально для добавления задержки между методами в заданной очереди jQuery. Нет возможности отменить задержку. Например, если вы хотите, чтобы изображение отображалось на одну секунду, отображалось его в течение пяти секунд, а затем исчезало на одну секунду, вы можете сделать следующее:
$("img").fadeIn(1000).delay(5000).fadeOut(1000);
setTimeout
лучше всего использовать для всего остального.
Наконец, если вам нужно повторно выполнить код после указанной задержки, тогда setInterval
больше подходит для этой работы. Вы можете прочитать больше об этой функции здесь .
Вывод
В этой статье я продемонстрировал, как использовать setTimeout
для задержки выполнения функции. Я также показал, как передавать параметры в setTimeout
, поддерживать значение this
внутри своего обратного вызова, а также как отменить таймер.
Если вы хотите узнать больше, в SitePoint Premium есть целая библиотека книг по JavaScript .
Если вы хотите обсудить содержание этой статьи, пожалуйста, сделайте это в комментариях. Однако, если вы столкнулись с проблемой кодирования, касающейся использования setTimeout
(или чего-то еще, действительно), тогда, пожалуйста, перейдите на форумы SitePoint . Вы можете войти с помощью (Google, Facebook, Twitter, Yahoo, GitHub или путем создания учетной записи). Затем перейдите на форум JavaScript и начните обсуждение вашей проблемы.