Примеры jquery-функции settimeout()

Пример из реального мира

На прошлой неделе я опубликовал статью о том, как создать бота в Twitter в 38 строчек кода. Единственной причиной, по которой код в этой статье работал, был API от Twitter. Когда вы делаете запросы по API, вам нужно подождать ответа, перед тем как вы сможете как-то с ним работать и соответственно на него воздействовать. Вот то, как выглядит сам запрос.

T.get('search/tweets', params, function(err, data, response) {if(!err){// This is where the magic will happen} else {console.log(err);}})

просто означает то, что мы делаем get запрос к Twitter.

У этого запроса есть три параметра: , которые служит маршрутом для нашего запроса, которые являются параметрами поиска и дальше идёт анонимная функция, которая и является колбэком.

Колбэк тут крайне важен, так как нам нужно подождать ответа сервера, перед тем как идти дальше в выполнении кода. Мы понятия не имеем, будет ли наш API запрос успешным или нет, так что после отправки наших параметров к через запрос — мы ждём. Как только Twitter ответит, вызовется наша callback-функция. Twitter либо отправит объект (т.е. ошибку) или объект . В нашем колбэке мы можем применить , чтобы определить был ли наш запрос проведен успешно или нет, а за тем уже соответственно работать с новыми данными.

Таймеры setTimeout и setInterval

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

Это и . Они позволят вам запустить кусок JavaScript кода в определенный момент в будущем. Такой подход называется “отложенным вызовом”. Далее вы узнаете как работают эти два метода и увидите несколько практических примеров.

The Problem with this

Code executed by is run in a separate execution context to the function from which it was called. This is problematic when the context of the keyword is important:

The reason for this output is that, in the first example, points to the object, whilst in the second example points to the global object (which doesn’t have a property).

To counteract this problem, there are various measures …

Explicitly Set the Value of

You can do this using bind, a method which creates a new function that, when called, has its keyword set to the provided value (in our case, the object). This would give us:

Note: was introduced in ECMAScript 5, so will only work in . You can read more about it (and other methods of setting the value of ) .

Use a Library

Many libraries come with built-in functions to address this issue. For example, jQuery’s jQuery.proxy() method. This takes a function and returns a new one that will always have a particular context. In our case, that would be:

setInterval()

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

setInterval ( expression, interval );

Но разница тут вот в чём. запускает только единожды, в то время, как продолжает запускать на регулярной основе после заданного временного интервала, пока вы не скажете стоп.

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

// Hello показывается каждые 3 секундыlet timerId= setInterval(() => alert('Hello'), 3000);// Повторения прекращаются после 6 секунд с id таймера.setTimeout(() => { clearInterval(timerId); alert('Bye'); }, 6000);

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

requestAnimationFrame()

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

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

До этого разработчики использовали и , чтобы создавать анимации. Проблема тут была в том, что для того, чтобы анимации были плавными, браузер зачастую отрисовывал кадры быстрее, чем они могут показаться на экране. Что вело к ненужным вычислениям. Также ещё одной проблемой в использовании или было то, что эти анимации продолжали работать, даже если страница не находилась в поле видимости пользователя.

Значения параметров

Параметр
Описание
function
Функция, которая будет многократно выполняться после истечения таймера.
delay
Время в миллисекундах, которое таймер должен ждать перед выполнением указанной функции или кода. Если этот параметр опущен, то используется значение 0, оно означает, что выполнение должно произойти немедленно, или, точнее, как можно скорее (как только завершат работу все обработчики событий). Если этот параметр меньше 4, то используется значение 4

Обратите внимание, что в любом случае фактическая задержка может быть больше, чем предполагалось, причины задержек перечислены ниже в примерах.
param1, …, paramX
Дополнительные параметры, передаваемые функции, указанной функцией или кодом, по истечении таймера. Передача дополнительных параметров функции в первом синтаксисе не работает в Internet Explorer 9 и ниже

Если вы хотите включить эту функцию в этом браузере, необходимо использовать полифилл.
code
Альтернативный синтаксис, который позволяет включать строку вместо функции, которая компилируется и выполняется по истечении таймера. Этот синтаксис не рекомендован к использованию в связи с угрозой безопасности.

Зачем нам вообще колбэки?

По одной простой и важной причине — JavaScript это событийно-ориентированный язык. Это говорит нам о том, что вместо ожидания ответа для последующего шага, JavaScript продолжит выполнение, следя за другими событиями (ну или ивентам, кому как удобнее)

Давайте взглянем на простой пример:

function first(){console.log(1);}function second(){console.log(2);}first();second();

Как вы и ожидали, функция выполнится первой, а функция second выполнится второй — все это выдаст в консоль следующее:

// 1// 2

Но что, если функция будет содержать код, который не может быть немедленно выполнен. Для примера, API запрос, где нам нужно отправить информацию, а затем подождать ответ? Чтобы симулировать такое действие, мы применим (дальше будет подробнее про него), который является функцией JavaScript, вызывающей другую функцию после определенного количества времени. То есть, мы задержим нашу функцию на 500 миллисекунд, чтобы симулировать API запрос. Таким образом, наш новый код будет выглядеть так:

function first(){// Симулируем задержку кодаsetTimeout( function(){console.log(1);}, 500 );}function second(){console.log(2);}first();second();

Пока что совершенно неважно, понимаете ли вы то, как работает. Всё, что важно — это то, чтобы вы увидели, что мы отсрочили на 500 миллисекунд

И так, что случится, когда мы вызовем наши функции?

first();second();// 2// 1

Пусть даже мы и вызываем первой, мы выводим в лог результат этой функции, после функции .

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

Так зачем вам это? А затем, что вы не можете просто вызывать одну функцию за другой и надеяться, что они выполнятся в правильном порядке. Колбэки это способ убедиться в том, что конкретный код не выполняется перед другим отрезком кода, который ещё не закончил своё выполнение.

Using Arrow Functions with setTimeout

Arrow functions were introduced with ES6. They have a much shorter syntax than a regular function:

You can, of course, use them with , but there’s one gotcha to be aware of — namely, that arrow functions don’t have their own value. Instead, they use the value of the enclosing lexical context.

Using a regular function:

Using an arrow function:

In the second example, points to the global object (which again, doesn’t have a property).

This can trip us up when using arrow functions with . Previously we saw how we can supply a function called in a with the correct value:

This won’t work when using an arrow function in the method, as the arrow function doesn’t have its own value. The method will still log .

Cleaner Code with Arrow Functions and setTimeout

However, because arrow functions don’t have their own value, it can also work to our advantage.

Consider code like this:

It can be rewritten more concisely with an arrow function:

If you’d like a primer on arrow functions, please read “ES6 Arrow Functions: Fat and Concise Syntax in JavaScript”.

Nested setTimeout

There are two ways of running something regularly.

One is . The other one is a nested , like this:

The above schedules the next call right at the end of the current one .

The nested is a more flexible method than . This way the next call may be scheduled differently, depending on the results of the current one.

For instance, we need to write a service that sends a request to the server every 5 seconds asking for data, but in case the server is overloaded, it should increase the interval to 10, 20, 40 seconds…

Here’s the pseudocode:

And if the functions that we’re scheduling are CPU-hungry, then we can measure the time taken by the execution and plan the next call sooner or later.

Nested allows to set the delay between the executions more precisely than .

Let’s compare two code fragments. The first one uses :

The second one uses nested :

For the internal scheduler will run every 100ms:

Did you notice?

The real delay between calls for is less than in the code!

That’s normal, because the time taken by ‘s execution “consumes” a part of the interval.

It is possible that ‘s execution turns out to be longer than we expected and takes more than 100ms.

In this case the engine waits for to complete, then checks the scheduler and if the time is up, runs it again immediately.

In the edge case, if the function always executes longer than ms, then the calls will happen without a pause at all.

And here is the picture for the nested :

The nested guarantees the fixed delay (here 100ms).

That’s because a new call is planned at the end of the previous one.

Garbage collection and setInterval/setTimeout callback

When a function is passed in , an internal reference is created to it and saved in the scheduler. It prevents the function from being garbage collected, even if there are no other references to it.

For the function stays in memory until is called.

There’s a side-effect. A function references the outer lexical environment, so, while it lives, outer variables live too. They may take much more memory than the function itself. So when we don’t need the scheduled function anymore, it’s better to cancel it, even if it’s very small.

More Examples

Example

You can also refer to a «named» function; Alert «Hello» every 3 seconds (3000 milliseconds):

var myVar;function myFunction() {  myVar = setInterval(alertFunc, 3000);}function alertFunc() {  alert(«Hello!»);}

Example

Display the current time (the setInterval() method will execute the function
once every 1 second, just like a digital watch):

var myVar = setInterval(myTimer, 1000);function myTimer()
{  var d = new Date();  var t = d.toLocaleTimeString();
 
document.getElementById(«demo»).innerHTML = t;}

Example

Using clearInterval() to stop time in the previous example:

var myVar = setInterval(myTimer, 1000);function myTimer()
{  var d = new Date();  var t = d.toLocaleTimeString();
  document.getElementById(«demo»).innerHTML = t;}function myStopFunction()
{  clearInterval(myVar);}

Example

Using setInterval() and clearInterval() to create a dynamic progress bar:

function move() {  var elem = document.getElementById(«myBar»);   var width = 0;  var id = setInterval(frame, 10);  function frame() {    if (width == 100) {      clearInterval(id);    } else {      width++;       elem.style.width = width + ‘%’;
    }  }}

Example

Toggle between two background colors once every 300 milliseconds:

var myVar = setInterval(setColor, 300);function setColor() {  var x = document.body;  x.style.backgroundColor = x.style.backgroundColor == «yellow» ? «pink» : «yellow»;}
function stopColor() {  clearInterval(myVar);}

Example

Pass parameters to the alertFunc function (does not work in IE9 and earlier):

var myVar;function myStartFunction() {  myVar = setInterval(alertFunc, 2000, «First param», «Second param»);}

However, if you use an anonymous function, it will work in
all browsers:

var myVar;function myStartFunction() {  myVar = setInterval(function(){ alertFunc(«First param», «Second param»); }, 2000);
}

More Examples

Example

You can also refer to «named» function; Display an alert box after 3 seconds (3000 milliseconds):

var myVar;function myFunction() {  myVar = setTimeout(alertFunc, 3000);}function alertFunc() {  alert(«Hello!»);}

Example

Display a timed text:

var x = document.getElementById(«txt»);setTimeout(function(){ x.value = «2 seconds» }, 2000);setTimeout(function(){ x.value = «4 seconds» }, 4000);setTimeout(function(){ x.value = «6 seconds» }, 6000);

Example

Open a new window and close the window after three seconds (3000
milliseconds):

var myWindow = window.open(«», «», «width=200, height=100»);
myWindow.document.write(«<p>This is ‘myWindow'</p>»);setTimeout(function(){ myWindow.close() }, 3000);

Example

Using clearTimeout() to prevent the function to run:

var myVar;function myFunction() {  myVar = setTimeout(function(){ alert(«Hello») }, 3000);
}function myStopFunction() {  clearTimeout(myVar);}

Example

Count forever — but with the ability to stop the count:

function startCount()function stopCount()

Example

A clock created with timing events:

function startTime() {  var today = new Date();  var h = today.getHours();
  var m = today.getMinutes();  var s = today.getSeconds();
  // add a zero in front of numbers<10  m = checkTime(m);  s = checkTime(s);
  document.getElementById(«txt»).innerHTML = h+ «:» + m + «:» + s;  t = setTimeout(function(){ startTime() }, 500);
}function checkTime(i) {  if (i<10) {    i = «0» + i;
  }  return i;}

Example

Pass parameters to the alertFunc function (does not work in IE9 and earlier):

var myVar;function myStartFunction() {  myVar = setTimeout(alertFunc, 2000, «First param», «Second param»);}

However, if you use an anonymous function, it will work in
all browsers:

var myVar;function myStartFunction() {  myVar = setTimeout(function(){ alertFunc(«First param», «Second param»); }, 2000);
}

Прозрачное кеширование

Представим, что у нас есть функция , выполняющая ресурсоёмкие вычисления, но возвращающая стабильные результаты. Другими словами, для одного и того же она всегда возвращает один и тот же результат.

Если функция вызывается часто, то, вероятно, мы захотим кешировать (запоминать) возвращаемые ею результаты, чтобы сэкономить время на повторных вычислениях.

Вместо того, чтобы усложнять дополнительной функциональностью, мы заключим её в функцию-обёртку – «wrapper» (от англ. «wrap» – обёртывать), которая добавит кеширование. Далее мы увидим, что в таком подходе масса преимуществ.

Вот код с объяснениями:

В коде выше – это декоратор, специальная функция, которая принимает другую функцию и изменяет её поведение.

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

Отделяя кеширующий код от основного кода, мы также сохраняем чистоту и простоту последнего.

Результат вызова является «обёрткой», т.е. «оборачивает» вызов в кеширующую логику:

С точки зрения внешнего кода, обёрнутая функция по-прежнему делает то же самое. Обёртка всего лишь добавляет к её поведению аспект кеширования.

Подводя итог, можно выделить несколько преимуществ использования отдельной вместо изменения кода самой :

  • Функцию можно использовать повторно. Мы можем применить её к другой функции.
  • Логика кеширования является отдельной, она не увеличивает сложность самой (если таковая была).
  • При необходимости мы можем объединить несколько декораторов (речь об этом пойдёт позже).

Code Examples to Analyze

For a more productive learning experience, we include useful code examples that you can practice using the setInterval JavaScript function.

The example below displays a popup alert every 2 seconds:

Example Copy

Now, this next example finds an HTML element with an ID , and changes its text to show the current time every second. In other words, it works like a digital clock:

Example Copy

While this next example works exactly like the one above, it has a method. If you ran the function, it would stop the clock:

Example Copy

You can you use the code in the example below to modify the width of a specified element until it’s exactly 100px wide:

Example Copy

Our last example toggles the background color from lime to red until the function is executed:

Example Copy

Методы setTimeout() и clearTimeout()

Метод предназначен для вызова кода на языке JavaScript после указанного количества миллисекунд.

Метод имеет два обязательных параметра:

  • — строка, содержащая код на языке JavaScript, который будет вызван в момент срабатывания таймера;
  • — указывается количество миллисекунд через которые данный таймер сработает.

Для прекращения работы таймера, т.е. для предотвращения вызова кода на языке JavaScript, хранящегося в первом параметре метода , используйте метод . Данный метод () содержит один обязательный параметр — это уникальный идентификатор () таймера, который можно получить как результат выполнения метода . Также таймер прекращает свою работу при закрытии окна.

//запустим таймер и получим его идентификатор, который будет храниться в переменной myTimer
//данный таймер выведет сообщение через 4 секунды после выполнения этой строчки
var myTimer = window.setTimeout("alert('Сообщение');",4000);
//после установления таймера его можно остановить с помощью метода clearInterval().
//Для этого необходимо в качестве параметра данному методу передать идентификатор таймера, хранящийся в переменной myTimer.
clearTimeout(myTimer);

Например, создадим на странице 2 кнопки. При нажатии на первую кнопку на экране будет отображаться количество секунд, прошедших с момента её нажатия. При нажатии на вторую кнопку будем останавливать выполнение данного процесса.

<script>
  // глобальная переменная, хранящая количество секунд, прошедших с момента нажатия ссылки
  var count=0;
  // глобальная переменная, хранящая идентификатор таймера
  var timer;
  //функция, выполняет следующее:
  //1 - выводит значения переменной count в элемент с id="clock"
  //2 - увеличивает значения переменной на 1
  //3 - запускает таймер, который вызовет функцию timeCount() через 1 секунду
  function timeCount() {
    document.getElementById("countTime").innerHTML = count.toString();
    count++;
    timer = window.setTimeout(function(){ timeCount() },1000);
  }
  //функция проверяет выражение !timer по правилу лжи, если оно истинно, 
  //то вызывает функцию timeCount()
  function startCount() {
    if (!timer)
      timeCount();
  }
    //функция проверяет выражение timer по правилу лжи
	//Если оно истинно, то она вызывает метод clearTimeOut() для прекращения работы таймера
	//и присваивает переменной timer значение null
	function stopCount() {
      if (timer) {
        clearTimeout(timer);
        timer=null;
      }
    }
</script>
...
Счётчик: <span id="countTime"></span>
<br />
<a href="javascript:startCount()">3anycтить процесс</a>
<br />
<a href="javascript:stopCount()">Остановить процесс</a>

Переходим к нескольким аргументам с «func.apply»

Теперь давайте сделаем ещё более универсальным. До сих пор он работал только с функциями с одним аргументом.

Как же кешировать метод с несколькими аргументами ?

Здесь у нас есть две задачи для решения.

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

Есть много возможных решений:

  1. Реализовать новую (или использовать стороннюю) структуру данных для коллекции, которая более универсальна, чем встроенный , и поддерживает множественные ключи.
  2. Использовать вложенные коллекции: будет , которая хранит пару . Тогда получить мы сможем, вызвав .
  3. Соединить два значения в одно. В нашем конкретном случае мы можем просто использовать строку как ключ к . Для гибкости, мы можем позволить передавать хеширующую функцию в декоратор, которая знает, как сделать одно значение из многих.

Для многих практических применений третий вариант достаточно хорош, поэтому мы будем придерживаться его.

Также нам понадобится заменить на , чтобы передавать все аргументы обёрнутой функции, а не только первый.

Вот более мощный :

Теперь он работает с любым количеством аргументов.

Есть два изменения:

  • В строке вызываем для создания одного ключа из . Здесь мы используем простую функцию «объединения», которая превращает аргументы в ключ . В более сложных случаях могут потребоваться другие функции хеширования.
  • Затем в строке используем для передачи как контекста, так и всех аргументов, полученных обёрткой (независимо от их количества), в исходную функцию.

Вместо мы могли бы написать .

Синтаксис встроенного метода func.apply:

Он выполняет , устанавливая и принимая в качестве списка аргументов псевдомассив .

Единственная разница в синтаксисе между и состоит в том, что ожидает список аргументов, в то время как принимает псевдомассив.

Эти два вызова почти эквивалентны:

Есть только одна небольшая разница:

  • Оператор расширения позволяет передавать перебираемый объект в виде списка в .
  • А принимает только псевдомассив .

Так что эти вызовы дополняют друг друга. Для перебираемых объектов сработает , а где мы ожидаем псевдомассив – .

А если у нас объект, который и то, и другое, например, реальный массив, то технически мы могли бы использовать любой метод, но , вероятно, будет быстрее, потому что большинство движков JavaScript внутренне оптимизируют его лучше.

Передача всех аргументов вместе с контекстом другой функции называется «перенаправлением вызова» (call forwarding).

Простейший вид такого перенаправления:

При вызове из внешнего кода его не отличить от вызова исходной функции.

Wrapping Up

One potential caveat to be aware of is the fact that is asynchronous. It queues the function reference it receives to run once the current call stack has finished executing. It doesn’t, however, execute concurrently, or on a separate thread (due to JavaScript’s single-threaded nature).

Although we’re calling with a zero second delay, the numbers are still logged out of order. This is because when ‘s timer has expired, the JavaScript engine places its callback function in a queue, behind the other statements, to be executed.

If you’d like to learn more about what happens when JavaScript runs, I highly recommend this video from JSConf 2014: What the heck is the event loop anyway?

requestAnimationFrame()

You should also be aware of requestAnimationFrame. This method tells the browser that you wish to call a specified function before the next repaint.

When making animations, we should favor over using , as it will fire roughly sixty times a second, as opposed to , which is called after a minimum of milliseconds. By using we can avoid changing something twice between two frame updates.

Here’s an example of how to use to animate a element across the screen:

You could, of course, achieve the same thing using :

But as mentioned, using offers various advantages, such as allowing the browser to make optimizations and stopping animations in inactive tabs.

See the Pen
Animation with requestAnimationFrame by SitePoint (@SitePoint)
on CodePen.

jQuery.delay()

Finally, I’d like to clear up any confusion between the use of the native JavaScript function and jQuery’s delay method.

The method is meant specifically for adding a delay between methods in a given jQuery queue. There is no possibility to cancel the delay. For example, if you wanted to fade an image into view for one second, have it visible for five seconds, and then fade it out for a period of one second, you could do the following:

is best used for everything else.

Note: if you need to repeatedly execute code after a specified delay, then is more suited to the job. You can read more about this function here.

Syntax

From the MDN documentation, the syntax for is as follows:

where:

  • is a numerical ID, which can be used in conjunction with clearTimeout to cancel the timer.
  • refers to the Window interface or the WorkerGlobalScope interface.
  • is the function to be executed after the timer expires.
  • is an alternative syntax that allows you to include a string instead of a function, which is compiled and executed when the timer expires.
  • is the number of milliseconds by which the function call should be delayed. If omitted, this defaults to 0.
  • are additional arguments passed to the function specified by .

Note: the square brackets denote optional parameters.

setTimeout vs window.setTimeout

You’ll notice that the syntax above uses . Why is this?

Well, when running code in the browser, would refer to the global object. Both and refer to the same function, the only difference being that in the second statement we are referencing the method as a property of the object.

In my opinion, this adds complexity for little or no benefit. If you’ve defined an alternative method which would be found and returned in priority in the scope chain, then you’ve probably got bigger problems to worry about.

For the purposes of this tutorial, I’ll omit , but ultimately, which syntax you choose is up to you.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector