Примеры jQuery-функции setTimeout()

JavaScript timeout представляет собой нативную javascript-функцию, которая исполняет фрагмент кода после установленной временной задержки (в миллисекундах). Это может пригодиться, когда нужно вывести всплывающее окошко после того, как пользователь провел некоторое время на вашей странице. Или нужно, чтобы эффект при наведении курсора на элемент запускался лишь спустя какое-то время. Таким образом, можно избежать непреднамеренного запуска эффекта, если пользователь навел курсор случайно.

Простой пример setTimeout

Чтобы продемонстрировать действие этой функции, предлагаю взглянуть на следующее демо, в котором всплывающее окно появляется спустя две секунды после клика по кнопке.

Посмотреть демо

Синтаксис

В документации MDN приведен следующий синтаксис для setTimeout:

var timeoutID = window.setTimeout(func, [delay, param1, param2, ...]);
var timeoutID = window.setTimeout(code, [delay]);

Где:

  • timeoutID – числовой id, который можно использовать в сочетании с clearTimeout() для отключения таймера;
  • func – функция, которая должна быть выполнена;
  • code (в альтернативном синтаксисе) – строка кода, которую нужно исполнить;
  • delay – длительность задержки в миллисекундах, после которой будет запущена функция. По умолчанию установлено значение 0.

setTimeout vs window.setTimeout

В приведенном выше синтаксисе используется window.setTimeout. Почему?

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

Лично я считаю, что это лишь сильно усложняет код. Если бы мы определили альтернативный метод JavaScript timeout, который может быть найден и возвращен в приоритетном порядке, то столкнулись бы с еще большими проблемами.

В данном руководстве я не хочу связываться с объектом window, но в целом, вы сами решаете, какой синтаксис стоит использовать.

Примеры использования

setTimeout принимает ссылки на функцию в качестве первого аргумента.

Это может быть название функции:

function explode(){
  alert("Boom!");
}
setTimeout(explode, 2000);

Переменная, которая обращается к функции:

var explode = function(){
  alert("Boom!");
};
setTimeout(explode, 2000);

Или же анонимная функция:

setTimeout(function(){
  alert("Boom!");
}, 2000);

Но я не рекомендую так делать по следующим причинам:

  • Такой код плохо воспринимается, а, следовательно, его сложно будет модернизировать или отладить;
  • Он предполагает использование метода eval(), который может стать потенциальной уязвимостью;
  • Этот метод работает медленнее других, так как ему требуется запускать JavaScript-интерпретатор.

Также обратите внимание, что для тестирования кода мы используем метод alert для JavaScript timeout.

Передаем параметры в setTimout

В первом (к тому же, кроссбраузерном) варианте мы передаем параметры в callback-функцию, исполняемую при помощи setTimeout.

В следующем примере мы выделяем случайное приветствие из массива greetings и передаем его в качестве параметра функции greet(), которая исполняется setTimeout с задержкой в 1 секунду:

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);

Посмотреть демо

Альтернативный метод

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

Опираясь на предыдущий пример, мы получаем:

setTimeout(greet, 1000, randomGreeting);

Этот метод не будет работать в IE 9 и ниже, где передаваемые параметры расцениваются как 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, а во втором примере - указывает на глобальный объект window, у которого отсутствует свойство firstName.

Чтобы избавиться от этой нестыковки, можно воспользоваться несколькими методами:

Принудительно установить значение this

Это можно сделать при помощи bind() – метода, который создает новую функцию, которая при вызове в качестве значения ключа this использует определенное значение. В нашем случае - указанный объект person. Это в результате дает нам:

setTimeout(person.introduce.bind(person), 50);

Примечание: метод bind был представлен в ECMAScript 5, а значит, что он будет работать только в современных браузерах. В других при его применении вы получите ошибку выполнения JavaScript «function timeout error».

Использовать библиотеку

Многие библиотеки включают в себя встроенные функции, необходимые для решения проблемы с this. Например, метод jQuery.proxy(). Он берет функцию и возвращает новую, в которой всегда будет использовать определенный контекст. В нашем случае, контекстом будет:

setTimeout($.proxy(person.introduce, person), 50);

Посмотреть демо

Отключение таймера

Возвращенное значение setTimeout представляет собой числовой id, который можно использовать для отключения таймера при помощи функции clearTimeout():

var timer = setTimeout(myFunction, 3000);
clearTimeout(timer);

Давайте посмотрим на нее в действии. В следующем примере, если кликнуть по кнопке «Start countdown», начнется обратный отсчет. После того, как он завершится, котята получат свое. Но если нажать кнопку «Stop countdown», таймер JavaScript timeout будет остановлен и сброшен.

Посмотреть пример

Подведем итоги

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

console.log(1);
setTimeout(function(){
  console.log(2);
  }, 0);
console.log(3);

// Outputs: 1, 3, 2

Многие также путают использование JavaScript-функции setTimeout, и jQuery-метода delay. Метод delay предназначен для установки временной задержки между методами в заданной очереди jQuery. Задержку отметить невозможно.

К примеру, если вы хотите затемнить изображение на секунду, сделать его видимым на 5 секунд, а затем снова затемнить на 1 секунду, то придется сделать следующее:

$("img").fadeIn(1000).delay(5000).fadeOut(1000);

Все же лучше использовать JavaScript timeout для чего-то другого.

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

В завершение

В этой статье я попытался показать, как использовать setTimeout для отсрочки исполнения функции. К тому же я рассказал, как вносить параметры в setTimeout, работать со значением this внутри callback-функции и об отмене таймера.