Node js setinterval: Таймеры в Node.js | Node.js
Таймеры в Node.js | Node.js
Edit on GitHub
Модуль таймеров в Node.js содержит функции, которые выполняют код по истечении
заданного периода времени. Таймеры не нужно импортировать через require()
, так как
все методы доступны глобально для эмуляции браузерного JavaScript API.
Для того, чтобы полностью понять когда будут выполняться функции таймера, имеет смысл
прочитать об Event Loop в Node.js.
API Node.js предоставляет несколько способов планирования кода, который нужно
выполнить, в какой-то момент в будущем. Приведенные ниже функции могут показатья знакомыми, так как
они доступны в большинстве браузеров, но Node.js на самом деле предоставляет
свою реализацию этих методов. Таймеры очень тесно интегрируются с системой, и, несмотря на то,
что API Node.js отражает API браузера, все равно имеются некоторые различия в реализации.
setTimeout()
может использоваться для планирования выполнения кода после назначенного
количества миллисекунд. Эта функция аналогична window. setTimeout()
из JavaScript API браузера, однако строка кода не может передаваться
в качестве аргумента для выполнения.
setTimeout()
первым параметром принимает функцию, которую нужно выполнить, и задержку в миллисекундах,
как число, в качестве второго параметра. Также можно перечислить дополнительные аргументы и они
будут переданы функции. Вот пример этого:
function myFunc(arg) {
console.log(`arg was => ${arg}`);
}
setTimeout(myFunc, 1500, 'funky');
Функция myFunc()
выполнится через время, максимально приближенное к
1500 миллисекундам (или 1.5 секунды), из-за вызова setTimeout()
.
Нельзя полагаться на то, что тайм-аут выполнится после этого точного количества миллисекунд.
Это связано с тем, что другой исполняемый код, который блокирует или удерживает цикл событий,
отодвигает выполнение тайм-аута на задний план. Единственной гарантией является то, что
тайм-аут не будет выполнен раньше, чем заданный интервал.
setTimeout()
возвращает объект Timeout
, который можно использовать в качестве ссылки
на тайм-аут, который был установлен. Этот объект можно использовать для отмены тайм-аута (см. clearTimeout()
ниже), а также для изменения поведения при выполнении (см. unref()
ниже).
setImmediate()
выполнит код в конце текущего цикла событий.
Этот код будет выполняться после любых операций ввода-вывода в текущем цикле событий и
перед любым запланированными таймерами для следующего цикла событий. Такое выполнение кода
можно рассматривать как «сразу после этого», то есть любой код, следующий за вызовом
функции setImmediate()
, будет выполняться до аргумента функции setImmediate()
.
Первым аргументом setImmediate()
будет функция, которую нужно выполнить. Все последующие
аргументы будут переданы функции при ее выполнении. Вот пример:
console.log('before immediate');
setImmediate((arg) => {
console. log(`executing immediate: ${arg}`);
}, 'so immediate');
console.log('after immediate');
Функция, переданная в setImmediate()
, будет выполнена после того,
как будет выполнен весь исполняемый код, и в консоли мы увидим следующее:
before immediate
after immediate
executing immediate: so immediate
setImmediate()
возвращает объект Immediate
, который можно использовать для отмены
запланированного immediate (см. clearImmediate()
ниже).
Примечание: Не путайте setImmediate()
и process.nextTick()
. Между ними есть
несколько основных различий. Во-первых, process.nextTick()
выполнится перед любыми Immediate
,
а также перед любыми запланированными операциями ввода/вывода. Во-вторых, process.nextTick()
не подлежит
отмене, имеется в виду, что после того как вы запланировали выполнение кода с помощью process.nextTick()
,
то его выполнение не может быть приостановлено, также как и с обычной функцией. Обратитесь к
этому руководству, чтобы лучше понять
работу process.nextTick()
.
Если у вас есть код, который нужно выполнить несколько раз, то можно использовать
для этого setInterval()
. setInterval()
принимает параметром функцию, которая будет
выполняться бесконечное количество раз с заданным интервалом в миллисекундах, сам интервал передается
вторым параметром. Как и в случае с setTimeout()
можно передавать дополнительные аргументы,
эти аргументы будут переданы функции при вызове. Также как и с setTimeout()
, задержка не может
быть гарантирована из-за операций, которые могут удерживать цикл событий, следовательно, нужно
рассматривать эту задержку как приблизительную. Смотрите пример ниже:
function intervalFunc() {
console.log('Cant stop me now!');
}
setInterval(intervalFunc, 1500);
В примере выше intervalFunc()
будет выполняться каждые 1500 миллисекунд
или 1.5 секунд, до тех пор, пока ее не остановят (см. ниже).
setInterval()
, также как и setTimeout()
возвращает объект Timeout
, который
можно использовать в качестве ссылки для изменения установленного интервала.
Отмена грядущего
Что нужно сделать, чтобы отменить Timeout
или Immediate
? setTimeout()
, setImmediate()
и
setInterval()
возвращают объект таймера, который можно использовать в качестве ссылки на установленные
Timeout
и Immediate
объекты. При передаче этого объекта в соответствующую функцию clear
— выполнение
этого объекта будет полностью остановлено. clearTimeout()
, clearImmediate()
и clearInterval()
— это те
самые специальные функции. Давайте посмотрим на пример ниже:
const timeoutObj = setTimeout(() => {
console.log('timeout beyond time');
}, 1500);
const immediateObj = setImmediate(() => {
console.log('immediately executing immediate');
});
const intervalObj = setInterval(() => {
console. log('interviewing the interval');
}, 500);
clearTimeout(timeoutObj);
clearImmediate(immediateObj);
clearInterval(intervalObj);
Оставляя тайм-ауты позади
Помните, что setTimeout
и setInterval
возвращают объект Timeout
.
У объекта Timeout
есть два метода, чтобы расширить свое поведение, это
unref()
и ref()
. Если есть объект Timeout
, запланированный с использованием функции set
,
то для этого объекта может быть вызвана unref()
. Это немного изменит поведение тем, что объект
Timeout
не выполнит запланированный код, если это последний код, который нужно выполнить. Объект Timeout
не будет удерживать процесс в ожидании выполнения.
Аналогичным образом, объект Timeout
, на котором был вызван unref()
,
может убрать это поведение, вызвав ref()
на том же Timeout
объекте, что затем
обеспечит его выполнение. Однако имейте в виду, что это не точно восстанавливает
исходное поведение по причинам производительности. Давайте взглянем на примеры ниже:
const timerObj = setTimeout(() => {
console.log('will i run?');
});
timerObj.unref();
setImmediate(() => {
timerObj.ref();
});
Далее по событийному циклу
В событийном цикле и таймерах можно найти гораздо больше информации, чем в
этом руководстве. Чтобы узнать больше о внутренностях цикла событий Node.js и о том,
как работают таймеры во время выполнения — взгляните на это руководство: The Node.js Event Loop, Timers, and process.nextTick().
setTimeout и setInterval | Прочее (Примеры)
Поскольку JavaScript поддерживает асинхронность, есть возможность запланировать выполнение функции, используя функции setTimeout
и setInterval
.
Замечание: Таймауты не являются частью стандарта ECMAScript, они были разработаны как раздел спецификации DOM.
function foo() {}
var id = setTimeout(foo, 1000) // возвращает число > 0
Функция setTimeout
возвращает идентификатор таймаута и планирует вызвать foo
через, примерно, тысячу миллисекунд. Функция foo
при этом будет вызвана ровно один раз.
В зависимости от разрешения таймера в используемом для запуска кода движке JavaScript, а также с учётом того, что JavaScript является однопоточным языком и посторонний код может заблокировать выполнение потока, нет никакой гарантии, что переданный код будет выполнен ровно через указанное в вызове setTimeout
время.
Переданная первым параметром функция будет вызвана как глобальный объект — это значит, что оператор this
в вызываемой функции будет ссылаться на этот самый объект.
function Foo() {
this.value = 42
this.method = function () {
// this ссылается на глобальный объект
console. log(this.value) // выведет в лог undefined
}
setTimeout(this.method, 500)
}
new Foo()
Замечание: Поскольку
setTimeout
принимает объект функции в качестве первого параметра, часто совершается ошибка в использованииsetTimeout(foo(), 1000)
, при котором будет использоваться возвращённое значение от вызова функцииfoo
, а не вызываться сама функцияfoo
. В большинстве случаев ошибка пройдёт незамеченной, а в случае если функция возвращаетundefined
,setTimeout
вообще не породит никакой ошибки.
Поочерёдные вызовы с использованием
setInterval
setTimeout
вызывает функцию единожды; setInterval
— как и предполагает название — вызывает функцию каждые X
миллисекунд. И его использование не рекомендуется.
В то время, когда исполняющийся код будет блокироваться во время вызова с таймаутом, setInterval
будет продолжать планировать последующие вызовы переданной функции. Это может (особенно в случае небольших интервалов) повлечь за собой выстраивание вызовов функций в очередь.
function foo() {
// что-то, что выполняется одну секунду
}
setInterval(foo, 100)
В приведённом коде foo
выполнится один раз и заблокирует этим главный поток на одну секунду.
Пока foo
блокирует код, setInterval
продолжает планировать последующие её вызовы. Теперь, когда первая foo
закончила выполнение, в очереди будут уже десять ожидающих выполнения вызовов foo
.
Разбираемся с потенциальной блокировкой кода
Самый простой и контролируемый способ — использовать setTimeout
внутри самой функции.
function foo() {
// что-то, выполняющееся одну секунду
setTimeout(foo, 100)
}
foo()
Такой способ не только инкапсулирует вызов setTimeout
, но и предотвращает от очередей блокирующих вызовов и при этом обеспечивает дополнительный контроль. Сама функция foo
теперь принимает решение, хочет ли она запускаться ещё раз или нет.
Очистка таймаутов вручную
Удаление таймаутов и интервалов работает через передачу соответствующего идентификатора либо в функцию clearTimeout
, либо в функцию clearInterval
— в зависимости от того, какая функция set...
использовалась для его получения.
var id = setTimeout(foo, 1000)
clearTimeout(id)
Очистка всех таймаутов
Из-за того, что встроенного метода для удаления всех таймаутов и/или интервалов не существует, для достижения этой цели приходится использовать брутфорс.
// удаляем "все" таймауты
for (var i = 1; i < 1000; i++) {
clearTimeout(i)
}
Вполне могут остаться таймауты, которые не будут захвачены этим произвольным числом; так что всё же рекомендуется следить за идентификаторами всех создающихся таймаутов, за счёт чего их можно будет удалять индивидуально.
Скрытое использование
eval
setTimeout
и setInterval
могут принимать строку в качестве первого параметра. Эту возможность не следует использовать никогда, поскольку изнутри при этом производится скрытый вызов eval
.
Замечание: Поскольку функции работы с таймаутами не определены в стандарте ECMAScript, точная внутренняя механика их работы может различаться от движка к движку. Известно, что Microsoft JScript использует конструктор
Function
вместоeval
.
function foo() {
// будет вызвана
}
function bar() {
function foo() {
// никогда не будет вызывана
}
setTimeout('foo()', 1000)
}
bar()
Поскольку eval
в этом случае не вызывается напрямую, переданная в setTimeout
строка будет выполнена в глобальной области видимости; так что локальная переменная foo
из области видимости bar
не будет выполнена.
По этим же причинам рекомендуется не использовать строку для передачи аргументов в функцию, которая должна быть вызвана из одной из двух функций, работающих с таймаутами.
function foo(a, b, c) {}
// НИКОГДА не делайте такого
setTimeout('foo(1,2, 3)', 1000)
// Вместо этого используйте анонимную функцию
setTimeout(function () {
foo(1, 2, 3)
}, 1000)
Замечание: При том, что синтаксис
setTimeout(foo, 1000, 1, 2, 3)
разрешено использовать, это крайне не рекомендуется, поскольку может привести к сложно распознаваемым ошибкам при работе с методами.
Заключение
Никогда не используйте строки как параметры setTimeout
или setInterval
. Это явный признак действительно плохого кода. Если вызываемой функции необходимо передавать аргументы, лучше передавать анонимную функцию, которая самостоятельно будет отвечать за сам вызов.
Кроме того, избегайте использования setInterval
в случаях, когда его планировщик может блокировать выполнение JavaScript.
Методы setTimeout и setInterval в Javascript
Видеоурок к статье
Введение
Для того, чтобы понять чем отличается метод setTimeout от setInterval давайте на примерах разберем, как работают эти методы.
Метод setTimeout
Метод setTimeout служит для того, чтобы вы смогли выполнить какой-нибудь Javascript сценарий с определенным интервалом.
Пример setTimeout:
Предположим, что вам нужно вывести модальное окно или какой-нибудь текст не сразу после загрузки страницы, а после того, как пользователь провел на вашей странице 10 секунд.
Создайте html файл с содержимым:
В данном примере, мы создали структуру документа html, создали div с id settimeout и подключили библиотеку JQuery.
Затем мы создали анонимный метод setTimeout и задали время выполнения через 10 секунд. Обратите внимание, что интервал задается в миллисекундах.
Внутри метода мы говорим, что хотим в div с id settimeout вставить html с текстом «Я появился через 10 секунд после загрузки страницы».
Стоит заметить, что setTimeout выполняется только один раз.
Метод setInterval
В отличии от setTimeout, метод setInterval выполняется до тех пор, пока не будет вызван метод clearInterval.
Для демонстрации метода setInterval, усложним немного пример.
Наш пример будет состоять из двух файлом ajax.php в котором мы будем хранить массив и возвращать его в формате json.
В файле index.html мы будем ajax’сом выводить новости из файла ajax.php с интервалом две секунды.
Файл ajax.php
В этом файле для примера мы будем хранить данные новостей. Первой строкой мы указываем кодировку utf-8 чтобы можно было корректно отображать русский язык. Далее мы создаем многомерный массив. И строкой json_encode мы преобразуем массив php в формат json для работы с этими данными в javascript.
Теперь дополните созданный файл из прошлого примера index.html следующим кодом:
Методом библиотеки Jquery $.ajax мы делаем фоновую загрузку данных из файла ajax.php. Далее мы создаем функцию setInterval где итеративно добавляем к переменной count единицу. Методом setInterval мы заменили цикл each, чтобы продемонстрировать setInterval.
Методом Jquery append добавляем к div c id setinterval данные. Когда новости заканчиваются, мы очищаем метод setInterval clearInterval, для того, чтобы он больше не выполнялся.
В результате вы увидите, что новости выводятся не все сразу, а с интервалом две секунды.
Выводы
Методы setInterval и setTimeout используются очень часто в работе веб-программиста.
Если у вас остались вопросы и непонятен принцип работы этих двух полезных методов javascript, посмотрите видеоурок статье.
Скачать примеры вы можете по этой ссылке.
Подписывайтесь на наш канал Youtube, вступайте в группу VK. Также вы можете подписаться на нашу почтовую рассылку, чтобы быть в курсе о новых и полезных материалах для веб-разработчика.
Читайте также
Все материалы с сайта wh-db.com и ru.wh-db.com защищены авторским правом. Копирование, публикация, продажа и распространение материала строго запрещены.
таймеров в Node.js | Node.js
Редактировать на GitHub
Модуль таймеров в Node.js содержит функции, которые выполняют код после набора
период времени. Таймеры не нужно импортировать через require ()
, поскольку
все методы доступны во всем мире для эмуляции JavaScript API браузера.
Чтобы полностью понять, когда будут выполняться функции таймера, рекомендуется
читайте на Node. js
Цикл событий.
API Node.js предоставляет несколько способов планирования выполнения кода на
какой-то момент после настоящего момента.Приведенные ниже функции могут показаться знакомыми,
поскольку они доступны в большинстве браузеров, но Node.js фактически предоставляет
собственная реализация этих методов. Таймеры очень тесно интегрируются
с системой, и несмотря на то, что API является зеркалом браузера
API, есть некоторые отличия в реализации.
setTimeout ()
может использоваться для планирования выполнения кода после назначенного
количество миллисекунд. Эта функция похожа на
window.setTimeout ()
из JavaScript API браузера, однако строка кода не может быть передана
быть исполненным.
setTimeout ()
принимает функцию для выполнения в качестве своего первого аргумента, а
миллисекундная задержка, определяемая числом в качестве второго аргумента. Дополнительный
Также могут быть включены аргументы, которые будут переданы функции. Здесь
пример этого:
function myFunc (arg) {
console.log (`arg was => $ {arg}`);
}
setTimeout (myFunc, 1500, «напуганный»);
Вышеупомянутая функция myFunc ()
будет выполняться как можно ближе к 1500
миллисекунды (или 1.5 секунд) по возможности за счет вызова setTimeout ()
.
Нельзя полагаться на то, что установленный интервал тайм-аута будет выполняться после
что точное число миллисекунд. Это потому, что другой исполняемый код,
блоки или удержания в цикле событий будут подталкивать выполнение тайм-аута
назад. Гарантия only заключается в том, что тайм-аут не выполнит раньше , чем
заявленный интервал тайм-аута.
setTimeout ()
возвращает объект Timeout
, который можно использовать для ссылки на
установленный тайм-аут.Этот возвращенный объект можно использовать для отмены тайм-аута (
см. clearTimeout ()
ниже), а также изменить поведение выполнения (см.
unref ()
ниже).
setImmediate ()
выполнит код в конце текущего цикла цикла событий.
Этот код будет выполнять после любых операций ввода-вывода в текущем цикле событий и
С до — любые таймеры, запланированные для следующего цикла событий. Выполнение этого кода
можно рассматривать как происходящее «сразу после этого», то есть любой код, следующий за
вызов функции setImmediate ()
будет выполняться до setImmediate ()
аргумент функции.
Первым аргументом функции setImmediate ()
будет функция, которую нужно выполнить. Любой
последующие аргументы будут переданы функции при ее выполнении.
Вот пример:
console.log («до немедленного»);
setImmediate ((arg) => {
console.log (`немедленное выполнение: $ {arg}`);
}, 'так немедленно');
console.log ('сразу после');
Вышеупомянутая функция, переданная в setImmediate ()
, будет выполняться после всех запускаемых
код выполнен, и вывод консоли будет:
до немедленного
сразу после
выполнение немедленно: так немедленно
setImmediate ()
возвращает объект Immediate
, который можно использовать для отмены
запланированное немедленное (см. clearImmediate ()
ниже).
Не путайте
setImmediate ()
сprocess.nextTick ()
. Есть
некоторые основные различия между ними. Во-первых, запускаетсяprocess.nextTick ()
.
перед любыеНепосредственные
, которые установлены, а также перед любым запланированным вводом-выводом.
Во-вторых,process.nextTick ()
не очищается, то есть один раз
код был запланирован для выполнения сprocess.nextTick ()
, выполнение
не может быть остановлен, как и при нормальной работе.Обратитесь к этому руководству
чтобы лучше понять работуprocess.nextTick ()
.
Если есть блок кода, который должен выполняться несколько раз, setInterval ()
можно использовать для выполнения этого кода. setInterval ()
принимает функцию
аргумент, который будет выполняться бесконечное количество раз с заданной миллисекундой
задержка в качестве второго аргумента. Как и setTimeout ()
, дополнительные аргументы
могут быть добавлены после задержки, и они будут переданы в вызов функции.Также, как и setTimeout ()
, задержка не может быть гарантирована из-за операций
которые могут удерживать цикл событий и поэтому должны рассматриваться как
примерная задержка. См. Пример ниже:
function intervalFunc () {
console.log («Не могу меня остановить!»);
}
setInterval (intervalFunc, 1500);
В приведенном выше примере intervalFunc ()
будет выполняться примерно каждые 1500
миллисекунды или 1,5 секунды, пока он не будет остановлен (см. ниже).
Как и setTimeout ()
, setInterval ()
также возвращает объект Timeout
, который
может использоваться для ссылки и изменения установленного интервала.
Что можно сделать, если необходимо отменить объект Timeout
или Immediate
?
setTimeout ()
, setImmediate ()
и setInterval ()
возвращают объект таймера
который может использоваться для ссылки на набор Timeout
или Immediate
object.
Путем передачи указанного объекта в соответствующую функцию clear
выполнение
этот объект будет полностью остановлен. Соответствующие функции:
clearTimeout ()
, clearImmediate ()
и clearInterval ()
.См. Пример
ниже пример каждого:
const timeoutObj = setTimeout (() => {
console.log ('тайм-аут вне времени');
}, 1500);
constmediateObj = setImmediate (() => {
console.log («немедленное выполнение»);
});
const intervalObj = setInterval (() => {
console.log ('опрос интервала');
}, 500);
clearTimeout (timeoutObj);
clearImmediate (непосредственныйObj);
clearInterval (intervalObj);
Помните, что Timeout
объектов возвращаются setTimeout
и setInterval
.Объект Timeout
предоставляет две функции, предназначенные для увеличения Timeout
поведение с unref ()
и ref ()
. Если запланирован объект Timeout
используя функцию set
, для этого объекта можно вызвать unref ()
. Это изменится
поведение немного, и не вызывать объект Timeout
, если он последний
код для выполнения . Объект Timeout
не поддерживает процесс, ожидая
выполнить.
Аналогичным образом объект Timeout
, для которого было вызвано unref ()
можно удалить это поведение, вызвав ref ()
для того же объекта Timeout
,
который затем обеспечит его выполнение. Однако имейте в виду, что это
не точно, восстанавливает исходное поведение по соображениям производительности. Видеть
ниже примеры обоих:
const timerObj = setTimeout (() => {
console.log ('я буду работать?');
});
timerObj.unref ();
setImmediate (() => {
timerObj.ref ();
});
Цикл событий и таймеры — это гораздо больше, чем это руководство
покрыл. Чтобы узнать больше о внутреннем устройстве Node.js
Цикл событий и то, как таймеры работают во время выполнения, проверьте
это руководство по Node.js: Цикл событий Node.js, таймеры и
process.nextTick ().
Таймеры Discover JavaScript
setTimeout ()
При написании кода JavaScript вы можете захотеть отложить выполнение функции.
Это задание setTimeout
. Вы указываете функцию обратного вызова, которая будет выполняться позже, и значение, выражающее, как позже вы хотите, чтобы она запускалась, в миллисекундах:
setTimeout (() => {
}, 2000)
setTimeout (() => {
}, 50)
Этот синтаксис определяет новую функцию. Вы можете вызвать любую другую функцию, которую хотите, или вы можете передать имя существующей функции и набор параметров:
const myFunction = (firstParam, secondParam) => {
}
setTimeout (myFunction, 2000, firstParam, secondParam)
setTimeout
возвращает идентификатор таймера.Обычно это не используется, но вы можете сохранить этот идентификатор и сбросить его, если хотите удалить это запланированное выполнение функции:
const id = setTimeout (() => {
}, 2000)
clearTimeout (идентификатор)
Нулевая задержка
Если вы укажете время ожидания на 0
, функция обратного вызова будет выполнена как можно скорее, но после выполнения текущей функции:
setTimeout (() => {
console.log ('после')
}, 0)
console.log ('до')
напечатает до
.
Это особенно полезно, чтобы избежать блокировки ЦП при выполнении интенсивных задач и позволить другим функциям выполняться при выполнении тяжелых вычислений с помощью функций очереди в планировщике.
Некоторые браузеры (IE и Edge) реализуют метод
setImmediate ()
, который выполняет те же самые функции, но он не является стандартным и недоступен в других браузерах. Но это стандартная функция в Node.js.
setInterval ()
setInterval
— это функция, аналогичная setTimeout
, с той разницей, что вместо однократного запуска функции обратного вызова она будет запускаться вечно с указанным вами интервалом времени (в миллисекундах):
setInterval (() => {
}, 2000)
Вышеупомянутая функция запускается каждые 2 секунды, если вы не прикажете ей остановиться, используя clearInterval
, передав ему идентификатор интервала, который вернул setInterval
:
const id = setInterval (() => {
}, 2000)
clearInterval (идентификатор)
Обычно вызывается clearInterval
внутри функции обратного вызова setInterval, чтобы позволить ей автоматически определять, следует ли ей запускать снова или останавливаться.Например, этот код запускает что-то, если App.somethingIWait не имеет значение , прибыло
:
const interval = setInterval (() => {
if (App.somethingIWait === 'прибыл') {
clearInterval (интервал)
возвращаться
}
}, 100)
Рекурсивный setTimeout
setInterval
запускает функцию каждые n миллисекунд, не обращая внимания на то, когда функция завершила свое выполнение.
Если функция всегда занимает одинаковое количество времени, все в порядке:
Может быть, функция занимает разное время выполнения, в зависимости от условий сети, например:
И, возможно, одно длинное выполнение перекрывает следующее:
Чтобы избежать этого, вы можете запланировать рекурсивный вызов setTimeout после завершения функции обратного вызова:
const myFunction = () => {
setTimeout (myFunction, 1000)
}
setTimeout (myFunction, 1000)
для реализации этого сценария:
setTimeout
и setInterval
доступны в Node.js через модуль Таймеры.
Node.js также предоставляет setImmediate ()
, что эквивалентно использованию setTimeout (() => {}, 0)
, в основном используется для работы с циклом событий Node.js.
set-interval-async — npm
Современная версия setInterval для обещаний и асинхронных функций, доступных в Node.js и браузерах.
setIntervalAsync
работает как на Node.js, так и в браузере, предоставляя тот же интерфейс
, что и setInterval
для асинхронных функций, при этом предотвращая перекрытие нескольких выполнений
во времени.
Node.js
Вы можете установить setIntervalAsync
, используя npm:
npm установить -E установить интервал-async
Или используя пряжу:
пряжа добавить -E set-interval-async
Теперь вам может потребоваться setIntervalAsync
в CommonJS:
// Выберите один из следующих вариантов: динамический, фиксированный, устаревший. const {setIntervalAsync} = require ('set-interval-async / dynamic') const {setIntervalAsync} = require ('set-interval-async / fixed') const {setIntervalAsync} = require ('set-interval-async / legacy') const {clearIntervalAsync} = require ('set-interval-async') // Или потребовать все сразу: const { динамический: {setIntervalAsync: setIntervalAsyncD}, исправлено: {setIntervalAsync: setIntervalAsyncF}, наследие: {setIntervalAsync: setIntervalAsyncL}, clearIntervalAsync } = require ('set-interval-async')
Или вы можете использовать синтаксис модулей ES6:
// Выберите один из следующих вариантов: динамический, фиксированный, устаревший.импортировать {setIntervalAsync} из 'set-interval-async / dynamic' импортировать {setIntervalAsync} из 'set-interval-async / fixed' импортировать {setIntervalAsync} из 'set-interval-async / legacy' импортировать {clearIntervalAsync} из 'set-interval-async' // Импортируем все сразу: импорт { динамический фиксированный, наследие, clearIntervalAsync } из 'set-interval-async' const {setIntervalAsync: setIntervalAsyncD} = динамический const {setIntervalAsync: setIntervalAsyncF} = фиксированный const {setIntervalAsync: setIntervalAsyncL} = устаревший
Браузер
В браузере вы можете добавить тег скрипта в свой HTML:
После загрузки скрипта в глобальном контексте будет определен модуль SetIntervalAsync
.
Теперь вы можете получить функцию setIntervalAsync
в любом из ее вариантов:
// Выберите один из следующих вариантов: динамический, фиксированный, устаревший. вар setIntervalAsync = SetIntervalAsync.dynamic.setIntervalAsync вар setIntervalAsync = SetIntervalAsync.fixed.setIntervalAsync var setIntervalAsync = SetIntervalAsync.legacy.setIntervalAsync // Также загружаем `clearIntervalAsync`. var clearIntervalAsync = SetIntervalAsync.clearIntervalAsync
В самом базовом сценарии вы можете использовать setIntervalAsync
так же, как и vanilla setInterval
. Например, такой код:
const { setIntervalAsync, clearIntervalAsync } = требуется ('установить интервал асинхронный / динамический') setIntervalAsync ( () => console.log ('Привет'), 1000 )
будет печатать «Hello» на консоли раз в секунду.Однако вы также можете предоставить асинхронную функцию (или функцию, возвращающую обещание):
постоянный таймер = setIntervalAsync ( async () => { console.log ('Привет') ждать doSomeWork () console.log ('Пока') }, 1000 ) // или эквивалентно константный таймер = setIntervalAsync ( () => { console.log ('Привет') вернуть doSomeWork (). затем ( () => console.log ('Пока') ) }, 1000 )
, который имеет добавленную аккуратность: теперь вы можете дождаться полной остановки цикла, прежде чем двигаться дальше, используя clearIntervalId
.Это особенно полезно, когда в конце модульного теста вы хотите убедиться, что асинхронный код не продолжает выполняться к тому времени, когда ваш менеджер тестирования перейдет к следующему.
it ('должен что-то проверить', async () => { константный таймер = setIntervalAsync ( / * некоторая асинхронная функция * /, / * некоторый интервал * / ) // Сделаем некоторые утверждения. ожидание clearIntervalAsync (таймер) // На этом этапе все таймеры очищены, а последний // выполнение также гарантированно завершится.})
Где setIntervalAsync
действительно хорош в тех ситуациях, когда данная асинхронная функция может занимать больше времени для вычисления, чем настроенный интервал, и, в то же время, небезопасно выполнять более одного раза за раз. Использование vanilla setInterval
нарушит ваш код в этом сценарии, тогда как setIntervalAsync
гарантирует, что функция никогда не будет выполняться более одного раза в одно и то же время. Например, рассмотрите:
async function processQueue (queue) { если (очередь.length === 0) { возвращаться } let head = queue [0] жду doSomeWork (голова) queue.shift () // Удаляет первый элемент. }
Вышеуказанная функция никогда не должна вызываться снова до завершения предыдущего выполнения. В противном случае первый элемент очереди будет обработан дважды, а второй элемент будет пропущен. Однако с setIntervalAsync
совершенно безопасно следующее:
setIntervalAsync (processQueue, 1000, очередь)
с setIntervalAsync
гарантирует, что функция никогда не будет выполняться более одного раза в любой момент.Вы можете выбрать, хотите ли вы использовать варианты Dynamic
или Fixed
, которые либо запускают каждое выполнение как можно скорее, либо устанавливают фиксированную задержку между концом одного выполнения и началом следующего. См. Динамический и фиксированный setIntervalAsync
для получения дополнительных сведений.
Чтобы увидеть полный набор примеров и инструкции по их запуску, посетите наш каталог примеров.
Если вам когда-либо приходилось иметь дело со странными, незаметными ошибками в результате использования setInterval
[1] в асинхронных функциях, или вам приходилось вручную переопределить setInterval
с помощью setTimeout
[2], чтобы предотвратить многократное выполнение одна и та же асинхронная функция от перекрытия, то эта библиотека станет заменой, которая решит ваши проблемы.
setInterval
выполняет заданную функцию многократно, один раз в фиксированное количество миллисекунд. Это может вызвать проблемы всякий раз, когда выполнение функции занимает больше времени, чем заданный интервал, поскольку она будет вызываться снова до завершения первого выполнения. Это часто проблема для функций без повторного входа; т.е. функции, которые не предназначены для одновременного выполнения нескольких операций.
setIntervalAsync
— это прямая замена setInterval
, который использует тот же API, но безопасен для использования с асинхронными функциями без повторного входа.
[1] https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout
[2] https://developer.mozilla.org/en-US/docs/Web/API / WindowOrWorkerGlobalScope / setInterval
setIntervalAsync
предоставляет две стратегии, которые можно использовать для предотвращения выполнения повторяющейся функции более одного раза в любой данный момент:
Dynamic : Если возможно, данная функция вызывается один раз каждые
интервала
миллисекунды.Если какое-либо выполнение занимает больше времени, чем желаемый интервал, следующее выполнение откладывается до завершения предыдущего и вызывается сразу после достижения этого условия.Фиксированный : Данная функция вызывается повторно, что гарантирует фиксированную задержку в
интервала
миллисекунды между концом одного выполнения и началом следующего.
Вы можете выбрать ту стратегию, которая лучше всего подходит для вашего приложения.В случае сомнений, стратегия Dynamic
, вероятно, будет достаточной для большинства случаев использования, сохраняя интервал как можно ближе к желаемому.
Вы можете просмотреть полный API на нашей странице документации.
Чтобы внести свой вклад в этот проект, вам необходимо сначала клонировать репозиторий:
git clone https://github.com/ealmansi/set-interval-async.git
Убедитесь, что Yarn глобально установлен в вашей системе,
установите все зависимости проекта и соберите проект:
Теперь вы можете запустить тесты и убедиться, что все работает правильно:
Если предыдущий шаг завершился успешно, вы готовы начать разработку этого проекта.
Pull-запросы приветствуются!
Вы можете убедиться, что ваш код соответствует стандартному стилю JavaScript, с помощью следующей команды:
MIT
Неожиданная остановка функции обратного вызова setInterval
· Проблема № 22149 · nodejs / node · GitHub
@apapirovski
С фоновым таймером я имею в виду, что это в основном функция, которая выполняет некоторую задачу, а затем перепланировывает себя с помощью setTimeout (). Без unref (), только setTimeout и иногда clearTimeout
Как это:
function doSomething () { PromiseReturningFunction ().затем ((данные) => { //сделать некоторые }). catch ((error) => { // регистрируем ошибку }). then (() => { setTimeout (doSomething, 5000); }); }
Я вызываю эту функцию один раз, когда приложение поднимается, а затем они должны продолжать работать, не ткнувшись извне. Отсюда «backgrund task», но я никогда не использую ничего, кроме setTimeout, для планирования.
Например, таймер api устанавливается в ответ на вызов api. Например, у меня есть вызов, который включает брандмауэр, который устанавливает таймер для автоматического отключения, если пользователь не подтвердит действие в течение 30 секунд.Этот таймер не работает. Соответствующий код выглядит следующим образом;
enableFirewall: (параметры) => { return getFwStatus (). then ((до) => { return execp ('sudo ufw --force enable'). then (() => { setDisableTimer (disableTime); }). then (() => { return getFwStatus (). then ((после) => { options.before = before; options.after = after; return addAuditLogEntry (параметры); }); }); }).тогда (() => { return disableTime; }). catch ((error) => { options.name = 'ошибка брандмауэра'; return disableFirewall (options) .catch (() => { вернуть execp ('sudo ufw disable') }). then (() => { return Promise.reject (ошибка); }); }); } function setDisableTimer (timeout) { cancelDisableTimer (); disableFirewallTimer = setTimeout (() => { disableFirewall ({пользователь: '- отключить таймер--'}); }, тайм-аут); } function cancelDisableTimer () { if (disableFirewallTimer! = null) { clearTimeout (disableFirewallTimer); disableFirewallTimer = ноль; } } function disableFirewall (options) { var options = options || {user: '--unknown user--'} вернуть getFwStatus ().then ((до) => { return execp ('sudo ufw disable'). then (() => { return getFwStatus (). then ((после) => { options.before = before; options.after = after; return addAuditLogEntry (параметры); }); }); }); }
Вызов api вызовет enableFirewall, и я действительно вижу при пошаговом выполнении кода, который он достигает и выполняет без ошибки
disableFirewallTimer = setTimeout (() => { disableFirewall ({пользователь: '- отключить таймер--'}); }, тайм-аут);
и что параметр тайм-аута действительно установлен на 30000, как я и ожидал.Но точка останова в анонимной функции никогда не срабатывает (и брандмауэр также не вызывается).
Одна из «фоновых задач», которая больше не работает
function keepNtpStatusFresh () { getNtpStatusOutputInternal (). then ((data) => { lastNtpCheck.data = данные; lastNtpCheck.when = новая дата (); }). catch ((error) => { lastNtpCheck.data = ноль; sails.log.error (ошибка); }). then (() => { setTimeout (keepNtpStatusFresh, 5000); }); } function getNtpStatusOutputInternal () { return execp (sails.\ s =] +) \ s + (\ S +) \ s + (\ S +) \ s + (\ S +) \ s + (\ S +) \ s + (\ S +) \ s + (\ S +) \ s + (\ S +) \ s + (\ S +) \ s + (\ S +) / gm); var match = re.exec (результат.stdout); вар серверов = []; while (match! = null) { server.push ({ тип: совпадение [1], удаленный: совпадение [2], refid: match [3], st: Число (совпадение [4]), t: совпадение [5], когда: Число (соответствует [6]), опрос: Число (совпадение [7]), охват: Число (совпадение [8]), задержка: Число (совпадение [9]), смещение: Число (совпадение [10]), джиттер: Число (совпадение [11]), }); match = re.exec (результат.stdout); } return {output: result.stdout, serverList: servers}; }); }
Кооперативный асинхронный JavaScript: таймауты и интервалы — Изучите веб-разработку
В этом руководстве рассматриваются традиционные методы, доступные в JavaScript для асинхронного выполнения кода по истечении заданного периода времени или через регулярный интервал (например, заданное количество раз в секунду), обсуждается, для чего они полезны, и рассматриваются их присущие вопросы.
Предварительные требования: | Базовая компьютерная грамотность, разумное понимание основ JavaScript. |
---|---|
Цель: | Чтобы понять асинхронные циклы и интервалы и для чего они нужны. |
В течение долгого времени веб-платформа предлагала программистам JavaScript ряд функций, которые позволяют им асинхронно выполнять код по истечении определенного временного интервала, а также повторно выполнять блок кода асинхронно, пока вы не скажете, чтобы он остановился. .
Эти функции:
-
setTimeout ()
- Выполняет указанный блок кода один раз по истечении указанного времени.
-
setInterval ()
- Повторно выполнять указанный блок кода с фиксированной временной задержкой между каждым вызовом.
-
requestAnimationFrame ()
- Современная версия
setInterval ()
. Выполняет указанный блок кода перед тем, как браузер в следующий раз перерисовывает отображение, позволяя запускать анимацию с подходящей частотой кадров независимо от среды, в которой она выполняется.
Асинхронный код, установленный этими функциями, выполняется в основном потоке (по истечении указанного таймера).
Важно знать, что вы можете (и часто будете) запускать другой код до выполнения вызова setTimeout ()
или между итерациями setInterval ()
. В зависимости от того, насколько интенсивно используются эти операции для процессора, они могут еще больше задержать выполнение асинхронного кода, поскольку любой асинхронный код будет выполняться только после после того, как станет доступным для основного потока.(Другими словами, когда стек пуст.) Вы узнаете больше по этому вопросу по мере прохождения этой статьи.
В любом случае эти функции используются для запуска постоянной анимации и другой фоновой обработки на веб-сайте или в приложении. В следующих разделах мы покажем вам, как их можно использовать.
Как мы уже говорили, setTimeout ()
выполняет определенный блок кода один раз по истечении заданного времени. Принимает следующие параметры:
- Функция для запуска или ссылка на функцию, определенную в другом месте.
- Число, представляющее интервал времени в миллисекундах (1000 миллисекунд равняется 1 секунде) ожидания перед выполнением кода. Если вы укажете значение
0
(или опустите значение), функция запустится при первой возможности. (См. Примечание ниже о том, почему он запускается «как можно скорее», а не «немедленно».) Подробнее о том, почему вы, возможно, захотите сделать это позже. - Ноль или более значений, представляющих любые параметры, которые вы хотите передать функции при ее запуске.
ПРИМЕЧАНИЕ: Указанное количество времени (или задержка) составляет , а не гарантированное время до выполнения, а минимальное время до выполнения.Обратные вызовы, которые вы передаете этим функциям, не могут выполняться, пока стек в основном потоке не станет пустым.
Как следствие, такой код, как setTimeout (fn, 0)
, будет выполняться, как только стек станет пустым, а не сразу . Если вы выполните код вроде setTimeout (fn, 0)
, но сразу после запуска цикла, который насчитывает от 1 до 10 миллиардов, ваш обратный вызов будет выполнен через несколько секунд.
В следующем примере браузер будет ждать две секунды перед выполнением анонимной функции, затем отобразит предупреждающее сообщение (посмотрите, как оно работает, и посмотрите исходный код):
let myGreeting = setTimeout (function () {
alert ('Здравствуйте, мистерВселенная! ');
}, 2000)
Указанные вами функции не обязательно должны быть анонимными. Вы можете дать своей функции имя и даже определить ее где-нибудь еще и передать ссылку на функцию в setTimeout () . Следующие две версии фрагмента кода эквивалентны первой:
let myGreeting = setTimeout (function sayHi () {
alert ('Здравствуйте, мистер Вселенная!');
}, 2000)
function sayHi () {
alert («Привет, мистер Вселенная!»);
}
let myGreeting = setTimeout (sayHi, 2000);
Это может быть полезно, если у вас есть функция, которую нужно вызывать как по таймауту, так и в ответ на событие, например.Но это также может просто помочь сохранить ваш код в порядке, особенно если обратный вызов тайм-аута занимает больше, чем несколько строк кода.
setTimeout ()
возвращает значение идентификатора, которое можно использовать для ссылки на тайм-аут позже, например, когда вы хотите его остановить. См. Раздел «Очистка тайм-аутов» (ниже), чтобы узнать, как это сделать.
Передача параметров в функцию setTimeout ()
Любые параметры, которые вы хотите передать функции, выполняемой внутри setTimeout ()
, должны быть переданы ей в качестве дополнительных параметров в конце списка.
Например, вы можете реорганизовать предыдущую функцию, чтобы она передавала привет любому переданному ей имени:
function sayHi (who) {
alert (`Привет, $ {who}!`);
}
Теперь вы можете передать имя человека в вызов setTimeout ()
в качестве третьего параметра:
let myGreeting = setTimeout (sayHi, 2000, «Мистер Вселенная»);
Очистка тайм-аутов
Наконец, если тайм-аут был создан, вы можете отменить его до истечения указанного времени, вызвав clearTimeout ()
, передав ему идентификатор вызова setTimeout ()
в качестве параметра.Итак, чтобы отменить указанный выше тайм-аут, вы должны сделать это:
clearTimeout (myGreeting);
Примечание : См. greeter-app.html
для более сложной демонстрации, которая позволяет вам установить имя человека, с которым можно поздороваться в форме, и отменить приветствие с помощью отдельной кнопки (см. Исходный код также).
setTimeout ()
отлично работает, когда вам нужно запустить код один раз через установленный период времени. Но что происходит, когда вам нужно запускать код снова и снова - например, в случае анимации?
Здесь появляется setInterval ()
.Это работает очень похоже на setTimeout ()
, за исключением того, что функция, которую вы передаете в качестве первого параметра, выполняется многократно с интервалом не менее одного миллисекунды, заданного вторым параметром, а не один раз. Вы также можете передать любые параметры, необходимые для выполняемой функции, в качестве последующих параметров вызова setInterval ()
.
Рассмотрим пример. Следующая функция создает новый объект Date ()
, извлекает из него строку времени, используя toLocaleTimeString ()
, а затем отображает ее в пользовательском интерфейсе.Затем он запускает функцию один раз в секунду, используя setInterval ()
, создавая эффект цифровых часов, которые обновляются один раз в секунду (см. Это в прямом эфире, а также см. Источник):
function displayTime () {
пусть дата = новая дата ();
let time = date.toLocaleTimeString ();
document.getElementById ('демонстрация'). textContent = время;
}
const createClock = setInterval (displayTime, 1000);
Как и setTimeout ()
, setInterval ()
возвращает идентифицирующее значение, которое вы можете использовать позже, когда вам нужно очистить интервал.
Очистка интервалов
setInterval ()
продолжает выполнять задачу вечно, если вы что-то с ней не сделаете. Вероятно, вам понадобится способ остановить такие задачи, иначе вы можете получить ошибки, когда браузер не сможет выполнить какие-либо другие версии задачи или если анимация, обрабатываемая задачей, завершилась. Вы можете сделать это так же, как останавливаете таймауты - передавая идентификатор, возвращенный вызовом setInterval ()
, в функцию clearInterval ()
:
const myInterval = setInterval (myFunction, 2000);
clearInterval (myInterval);
Активное обучение: создание собственного секундомера!
С учетом всего сказанного, у нас есть для вас вызов.Возьмите копию нашего примера setInterval-clock.html
и измените его, чтобы создать свой собственный простой секундомер.
Вам нужно отображать время, как и раньше, но в этом примере вам нужно:
- Кнопка «Пуск» для запуска секундомера.
- Кнопка «Стоп», чтобы приостановить / остановить его.
- Кнопка «Сброс» для сброса времени на
0
. - Отображение времени, показывающее количество прошедших секунд, а не фактическое время.
Вот вам несколько подсказок:
- Вы можете структурировать и стилизовать разметку кнопок по своему усмотрению; просто убедитесь, что вы используете семантический HTML с крючками, которые позволяют захватывать ссылки на кнопки с помощью JavaScript.
- Вероятно, вы захотите создать переменную, которая начинается с
0
, а затем увеличивается на единицу каждую секунду с использованием постоянного цикла. - Этот пример проще создать без использования объекта
Date ()
, как мы это делали в нашей версии, но с меньшей точностью - вы не можете гарантировать, что обратный вызов сработает ровно через1000
мс. Более точным способом было бы запуститьstartTime = Date.now ()
, чтобы получить точную метку времени, когда пользователь щелкнул кнопку запуска, а затем выполнитьDate.now () - startTime
, чтобы получить количество миллисекунд после нажатия кнопки запуска. - Вы также хотите вычислить количество часов, минут и секунд как отдельные значения, а затем отображать их вместе в строке после каждой итерации цикла. На втором счетчике вы можете отработать каждую из них.
- Как бы вы их рассчитали? Подумайте об этом:
- Количество секунд в часе
3600
. - Количество минут - это количество секунд, оставшееся после удаления всех часов, разделенное на
60
. - Количество секунд - это количество секунд, оставшееся после удаления всех минут.
- Количество секунд в часе
- Вы захотите включить начальный ноль в отображаемые значения, если сумма меньше
10
, чтобы они больше походили на традиционные часы / часы. - Чтобы приостановить секундомер, вам нужно очистить интервал. Чтобы сбросить его, вы захотите установить счетчик обратно на
0
, очистить интервал, а затем немедленно обновить отображение. - Вероятно, вам следует отключить кнопку запуска после ее однократного нажатия и включить ее снова после того, как вы остановили / сбросили ее. В противном случае многократное нажатие кнопки пуска применит к часам несколько
setInterval ()
с, что приведет к неправильному поведению.
При работе с setTimeout ()
и setInterval ()
следует помнить о нескольких моментах. Давайте рассмотрим их сейчас.
Рекурсивные таймауты
Есть еще один способ использования setTimeout ()
: вы можете вызвать его рекурсивно для повторного выполнения одного и того же кода вместо использования setInterval ()
.
В приведенном ниже примере используется рекурсивная функция setTimeout ()
для запуска переданной функции каждые 100
миллисекунды:
пусть i = 1;
setTimeout (function run () {
console.log (я);
i ++;
setTimeout (запустить, 100);
}, 100);
Сравните приведенный выше пример со следующим - здесь используется setInterval ()
для достижения того же эффекта:
пусть i = 1;
setInterval (function run () {
console.log (я);
я ++
}, 100);
Чем отличаются рекурсивные
setTimeout ()
и setInterval ()
?
Разница между двумя версиями приведенного выше кода невелика.
- Рекурсивный
setTimeout ()
гарантирует такую же задержку между выполнениями. (Например,100
мс в приведенном выше случае.) Код будет запущен, затем подождет100
миллисекунды, прежде чем он выполнится снова, поэтому интервал будет одинаковым, независимо от того, сколько времени требуется для выполнения кода. - Пример с использованием
setInterval ()
работает несколько иначе. Выбранный вами интервал включает в себя время, необходимое для выполнения кода, который вы хотите запустить.Скажем, выполнение кода занимает40
миллисекунды - тогда интервал составляет всего60
миллисекунды. - При рекурсивном использовании
setTimeout ()
каждая итерация может вычислять различную задержку перед запуском следующей итерации. Другими словами, значение второго параметра может указывать другое время в миллисекундах для ожидания перед повторным запуском кода.
Когда ваш код может занять больше времени, чем установленный вами интервал времени, лучше использовать рекурсивный setTimeout ()
- это сохранит постоянный временной интервал между выполнениями независимо от того, сколько времени потребуется для выполнения кода. выполнить, и вы не получите ошибок.
Немедленные тайм-ауты
Использование 0
в качестве значения для setTimeout ()
планирует выполнение указанной функции обратного вызова как можно скорее, но только после того, как будет запущен основной поток кода.
Например, приведенный ниже код (см. Его в реальном времени) выводит предупреждение, содержащее «Hello»
, а затем предупреждение, содержащее «World»
, как только вы нажимаете OK в первом предупреждении.
setTimeout (function () {
alert ('Мир');
}, 0);
alert ('Привет');
Это может быть полезно в случаях, когда вы хотите настроить запуск блока кода, как только завершится выполнение всего основного потока - поместите его в цикл событий async, чтобы он запускался сразу после этого.
Очистка с помощью clearTimeout () или clearInterval ()
clearTimeout ()
и clearInterval ()
оба используют один и тот же список записей для очистки. Интересно, что это означает, что вы можете использовать любой метод для очистки setTimeout ()
или setInterval ()
.
Для согласованности следует использовать clearTimeout ()
для очистки записей setTimeout ()
и clearInterval ()
для очистки записей setInterval ()
.Это поможет избежать путаницы.
requestAnimationFrame ()
- это специализированная функция цикла, созданная для эффективного запуска анимации в браузере. По сути, это современная версия setInterval ()
- она выполняет указанный блок кода перед тем, как браузер перерисовывает изображение, позволяя запускать анимацию с подходящей частотой кадров независимо от среды, в которой она выполняется.
Он был создан в ответ на предполагаемые проблемы с setInterval ()
, который, например, не работает с частотой кадров, оптимизированной для устройства, иногда отбрасывает кадры, продолжает работать, даже если вкладка не является активной вкладкой или анимация прокручивается со страницы и т. д.
(Подробнее об этом читайте в CreativeJS.)
Метод принимает в качестве аргумента обратный вызов, который должен быть вызван перед перерисовкой. Это общий шаблон, который вы увидите в нем:
.
function draw () {
requestAnimationFrame (рисовать);
}
рисовать();
Идея состоит в том, чтобы определить функцию, в которой обновляется ваша анимация (например, ваши спрайты перемещаются, счет обновляется, данные обновляются и т. Д.). Затем вы вызываете его, чтобы начать процесс. В конце функционального блока вы вызываете requestAnimationFrame ()
со ссылкой на функцию, переданную в качестве параметра, и это дает браузеру команду вызвать функцию снова при следующей перерисовке дисплея.Затем он выполняется непрерывно, поскольку код requestAnimationFrame ()
рекурсивно вызывает.
Примечание : Если вы хотите выполнить какую-то простую постоянную DOM-анимацию, CSS-анимация, вероятно, будет быстрее. Они рассчитываются непосредственно внутренним кодом браузера, а не JavaScript.
Если, однако, вы делаете что-то более сложное и включаете в себя объекты, которые не доступны напрямую внутри DOM (например, 2D Canvas API или объекты WebGL), requestAnimationFrame ()
в большинстве случаев является лучшим вариантом.
Как быстро движется ваша анимация?
Плавность анимации напрямую зависит от частоты кадров анимации и измеряется в кадрах в секунду (fps). Чем выше это число, тем плавнее будет выглядеть ваша анимация до определенной точки.
Поскольку большинство экранов имеют частоту обновления 60 Гц, максимальная частота кадров, к которой вы можете стремиться, составляет 60 кадров в секунду (FPS) при работе с веб-браузерами. Однако большее количество кадров означает больше обработки, которая часто может вызывать заикание и пропуски, также известные как пропущенных кадров или jank .
Если у вас есть монитор с частотой обновления 60 Гц и вы хотите достичь 60 кадров в секунду, у вас есть около 16,7 миллисекунд ( 1000/60
) на выполнение кода анимации для рендеринга каждого кадра. Это напоминание о том, что вам нужно помнить об объеме кода, который вы пытаетесь запустить во время каждого прохождения цикла анимации.
requestAnimationFrame ()
всегда пытается максимально приблизиться к этому магическому значению 60 FPS. Иногда это невозможно - если у вас действительно сложная анимация и вы запускаете ее на медленном компьютере, частота кадров будет меньше.Во всех случаях requestAnimationFrame ()
всегда будет делать все возможное с тем, что у него есть.
Чем requestAnimationFrame () отличается от setInterval () и setTimeout ()?
Давайте поговорим еще немного о том, чем метод requestAnimationFrame ()
отличается от других методов, используемых ранее. Глядя на наш код сверху:
function draw () {
requestAnimationFrame (рисовать);
}
рисовать();
Давайте теперь посмотрим, как сделать то же самое с помощью setInterval ()
:
function draw () {
}
setInterval (ничья, 17);
Как мы уже говорили ранее, вы не указываете временной интервал для requestAnimationFrame ()
.Просто он работает максимально быстро и плавно в текущих условиях. Браузер также не тратит время на его запуск, если анимация по какой-то причине выходит за пределы экрана и т. Д.
setInterval ()
, с другой стороны, требует указания интервала . Мы пришли к нашему окончательному значению 17 по формуле 1000 миллисекунд / 60 Гц , а затем округлили его в большую сторону. Округление - хорошая идея; если вы округлите в меньшую сторону, браузер может попытаться запустить анимацию со скоростью, превышающей 60 FPS, и в любом случае это не повлияет на плавность анимации.Как мы уже говорили ранее, стандартная частота обновления - 60 Гц.
Добавление отметки времени
Фактическому обратному вызову, переданному в функцию requestAnimationFrame ()
, также может быть задан параметр: значение отметки времени , которое представляет время с момента запуска requestAnimationFrame ()
.
Это полезно, поскольку позволяет запускать вещи в определенное время и с постоянным темпом, независимо от того, насколько быстрым или медленным может быть ваше устройство. Общий шаблон, который вы бы использовали, выглядит примерно так:
пусть startTime = null;
function draw (timestamp) {
if (! startTime) {
startTime = отметка времени;
}
currentTime = отметка времени - startTime;
requestAnimationFrame (рисовать);
}
рисовать();
Поддержка браузера
requestAnimationFrame ()
поддерживается в более поздних версиях браузеров, чем setInterval ()
/ setTimeout ()
.Интересно, что он доступен в Internet Explorer 10 и выше.
Итак, если вам не нужна поддержка более старых версий IE, нет особых причин не использовать requestAnimationFrame ()
.
Простой пример
Довольно теории! Создадим ваш собственный пример requestAnimationFrame ()
. Вы собираетесь создать простую «анимацию прядильщика» - такую, которую вы можете увидеть в приложении, когда оно подключено к серверу и т. Д.
Примечание : В реальном примере вам, вероятно, следует использовать анимацию CSS для запуска такой простой анимации.Однако такой пример очень полезен для демонстрации использования requestAnimationFrame ()
, и вы с большей вероятностью воспользуетесь этой техникой при выполнении чего-то более сложного, например, обновления отображения игры в каждом кадре.
Возьмите базовый шаблон HTML (например, этот).
Поместите пустой элемент
внутриПримените следующий CSS к шаблону HTML (любым удобным для вас способом). Это устанавливает красный фон на странице, устанавливает высоту
100%
высотывнутриhtml { цвет фона: белый; высота: 100%; } тело { рост: наследовать; цвет фона: красный; маржа: 0; дисплей: гибкий; justify-content: center; align-items: center; } div { дисплей: встроенный блок; font-size: 10rem; }
Вставьте элемент
Вставьте следующий код JavaScript в элемент
внутри константы,устанавливаете для переменнойrotateCount
значение0
,устанавливаете неинициализированную переменную,которая позже будет использоваться для хранения ссылки наrequestAnimationFrame()
call и установив для переменнойstartTime
значениеnull
,которое позже будет использоваться для хранения времени началаrequestAnimationFrame()
.const spinner=document.querySelector('div');пусть rotateCount=0;пусть startTime=null;пусть rAF;
Под предыдущим кодом вставьте функцию
draw()
,которая будет использоваться для хранения нашего кода анимации,который включает параметрtimestamp
:отрисовка функции(отметка времени){}
Внутри
draw()
добавьте следующие строки.Они определят время начала,если оно еще не определено(это произойдет только на первой итерации цикла),и установят дляrotateCount
значение,на которое будет вращаться счетчик(текущая временная метка,взять начальную временную метку,разделенную на три,чтобы не было слишком быстро):if(!StartTime){startTime=отметка времени;} rotateCount=(отметка времени-время начала)/3;
Под предыдущей строкой внутри
draw()
добавьте следующий блок-он проверяет,не превышает ли значениеrotateCount
значение359
(например.грамм.360
,полный круг).Если это так,он устанавливает значение по модулю 360(то есть остаток,оставшийся после деления значения на360
),поэтому круговая анимация может продолжаться непрерывно с разумным низким значением.Обратите внимание,что в этом нет строгой необходимости,но легче работать со значениями 0–359 градусов,чем со значениями вроде"128000 градусов"
.if(rotateCount>359){rotateCount%=360;}
- Затем под предыдущим блоком добавьте следующую строку,чтобы фактически повернуть счетчик:
вертушка.style.transform=`rotate ($ {rotateCount} deg)`;
В самом низу функции
draw()
вставьте следующую строку.Это ключ ко всей операции-вы устанавливаете определенную ранее переменную для активного вызоваrequestAnimation()
,который принимает функциюdraw()
в качестве своего параметра.Это запускает анимацию,постоянно выполняя функциюdraw()
со скоростью,близкой к 60 FPS,насколько это возможно.rAF=requestAnimationFrame(рисовать);
Под определением функции
draw()
добавьте вызов функцииdraw()
для запуска анимации.ничья();
Очистка вызова requestAnimationFrame()
Очистка вызова
requestAnimationFrame()
может быть выполнена путем вызова соответствующего методаcancelAnimationFrame()
.(Обратите внимание,что имя функции начинается с «cancel»,а не «clear»,как в случае с методами «set...».)Просто передайте ему значение,возвращенное вызовом
requestAnimationFrame()
для отмены,которое вы сохранили в переменнойrAF
:cancelAnimationFrame(rAF);
Активное обучение:запуск и остановка нашего счетчика
В этом упражнении мы хотели бы,чтобы вы протестировали метод
cancelAnimationFrame()
,взяв наш предыдущий пример и обновив его,добавив прослушиватель событий для запуска и остановки счетчик при щелчке мышью в любом месте страницы.Подсказки:
- Обработчик события
click
можно добавить к большинству элементов,включая документ.Имеет смысл поместить его в элемент
,если вы хотите максимизировать интерактивную область-событие всплывает до его дочерних элементов.
- Вы захотите добавить переменную отслеживания,чтобы проверить,вращается ли счетчик или нет,очистив кадр анимации,если он есть,и снова вызвать его,если это не так.
Регулировка анимации requestAnimationFrame()
Одно из ограничений
requestAnimationFrame()
состоит в том,что вы не можете выбрать частоту кадров.В большинстве случаев это не проблема,так как обычно вы хотите,чтобы ваша анимация работала как можно более плавно.Но как насчет того,чтобы создать олдскульную 8-битную анимацию?Это была проблема,например,в анимации ходьбы,вдохновленной островом обезьян,из нашей статьи про рисование графики:
В этом примере вы должны анимировать как положение персонажа на экране,так и отображаемый спрайт.В анимации спрайта всего 6 кадров.Если бы вы показывали разные кадры спрайта для каждого кадра,отображаемого на экране с помощью
requestAnimationFrame()
,Гайбраш двигал бы конечностями слишком быстро,и анимация выглядела бы нелепо.Таким образом,в этом примере регулируется скорость,с которой спрайт циклически повторяет свои кадры,используя следующий код:if(posX%13===0){if(sprite===5){спрайт=0;}еще{спрайт++;}}
Таким образом,код циклически повторяет спрайт только каждые 13 кадров анимации.
...Фактически,это примерно каждые 6,5 кадров,поскольку мы обновляем
posX
(положение персонажа на экране)на два кадра:if(posX>width/2){newStartPos=-((ширина/2)+102);posX=Math.ceil(newStartPos/13)*13;console.log(posX);}еще{posX+=2;}
Это код,который вычисляет,как обновлять позицию в каждом кадре анимации.
Метод,который вы используете для регулирования анимации,будет зависеть от вашего конкретного кода.Например,в предыдущем примере счетчика вы могли заставить его двигаться медленнее,увеличивая значение
rotateCount
только на единицу в каждом кадре вместо двух.В последнем разделе этой статьи вы создадите игру на реакцию для двух игроков.В игре будет два игрока,один из которых управляет игрой с помощью ключаA,а другой-с помощью ключаL.
Когда нажата кнопкаStart,счетчик,подобный тому,который мы видели ранее,отображается в течение случайного промежутка времени от 5 до 10 секунд.По истечении этого времени появится сообщение
«ИГРОКИ УХОДИ!!»
-как только это произойдет,первый игрок,который нажмет свою кнопку управления,выиграет игру.Давайте поработаем над этим:
Прежде всего,загрузите стартовый файл для приложения.Он содержит законченную структуру HTML и стили CSS,что дает нам игровую доску,которая показывает информацию двух игроков(как показано выше),но с счетчиком и параграфом результатов,отображаемым друг над другом.Вам просто нужно написать код JavaScript.
Внутри пустого элемента
на вашей странице начните с добавления следующих строк кода,которые определяют некоторые константы и переменные,которые вам понадобятся в остальной части кода:
const spinner=document.querySelector('. Spinner p');const spinnerContainer=document.querySelector('. spinner');пусть rotateCount=0;пусть startTime=null;пусть rAF;const btn=document.querySelector('кнопка');const результат=документ.querySelector('. результат');
По порядку это:
- Ссылка на счетчик,чтобы его можно было анимировать.
- Ссылка на элемент,содержащий счетчик,используемый для его отображения и скрытия.
- A счетчик оборотов.Это определяет,насколько вы хотите показывать вращение счетчика на каждом кадре анимации.
- Нулевое время начала.Это будет заполнено временем начала,когда счетчик начнет вращаться.
- Неинициализированная переменная для последующего хранения вызова
requestAnimationFrame()
,который анимирует счетчик.- Ссылка на кнопку «Пуск».
- Ссылка на параграф результатов.
Затем под предыдущими строками кода добавьте следующую функцию.Он принимает два числа и возвращает случайное число между ними.Это понадобится вам позже,чтобы сгенерировать случайный интервал тайм-аута.
функция случайная(мин.,Макс.){var num=Math.этаж(Math.random()*(max-min))+min;return num;}
Затем добавьте функцию
draw()
,которая анимирует счетчик.Это очень похоже на версию из предыдущего примера простого счетчика:отрисовка функции(отметка времени){if(!startTime){startTime=отметка времени;} rotateCount=(отметка времени-время начала)/3;if(rotateCount>359){rotateCount%=360;} spinner.style.transform='повернуть ('+rotateCount+'deg)';rAF=requestAnimationFrame(рисовать);}
Теперь пора настроить начальное состояние приложения при первой загрузке страницы.Добавьте следующие две строки,которые скрывают абзац результатов и контейнер счетчика с использованием
display:none;
.result.style.display='нет';spinnerContainer.style.display='нет';
Затем определите функцию
reset()
,которая возвращает приложение в исходное состояние,необходимое для повторного запуска игры после ее завершения.Добавьте в конец кода следующее:функция сброса(){btn.style.display='блок';result.textContent='';result.style.display='нет';}
Ладно,хватит подготовки!Пришло время сделать игру доступной!Добавьте в свой код следующий блок.Функция
start()
вызываетdraw()
,чтобы запустить вращение счетчика и отобразить его в пользовательском интерфейсе,скрывает кнопкуStart,чтобы вы не могли испортить игру,запустив ее несколько раз одновременно,и запускаетsetTimeout()
,который запускает функциюsetEndgame()
по прошествии случайного интервала от 5 до 10 секунд.Следующий блок также добавляет прослушиватель событий к вашей кнопке для запуска функцииstart()
при ее нажатии.btn.addEventListener(«щелчок»,запуск);function start(){рисовать();spinnerContainer.style.display='блок';btn.style.display='нет';setTimeout(setEndgame,случайный(5000,10000));}
Примечание:Вы увидите,что этот пример вызывает
setTimeout()
без сохранения возвращаемого значения.(Итак,не,пусть myTimeout=setTimeout(functionName,interval)
.)Это прекрасно работает,если вам не нужно очищать интервал/тайм-аут в любой момент.Если вы это сделаете,вам нужно будет сохранить возвращенный идентификатор!
Конечный результат предыдущего кода состоит в том,что при нажатии кнопкиStartотображается счетчик,и игроки вынуждены ждать произвольное количество времени,прежде чем их попросят нажать их кнопку.Эта последняя часть обрабатывается функцией
setEndgame()
,которую вы определите позже.Добавьте в свой код следующую функцию:
function setEndgame(){cancelAnimationFrame(rAF);spinnerContainer.style.display='нет';result.style.display='блок';result.textContent='ИГРОКИ УХОДИ !!';document.addEventListener('keydown',keyHandler);function keyHandler(e){пусть isOver=false;console.log(e.key);if(e.key==="a"){result.textContent='Игрок 1 выиграл !!';isOver=true;}else if(e.key==="l"){result.textContent='Игрок 2 выиграл !!';isOver=true;} if(isOver){document.removeEventListener('keydown',keyHandler);setTimeout(сброс,5000);}};}
Шагая через это:
- Сначала отмените анимацию счетчика с помощью
cancelAnimationFrame()
(всегда полезно очистить ненужные процессы)и скройте контейнер счетчика. - Затем отобразите абзац результатов и установите для его текстового содержания значение «ИГРОКИ ВПЕРЕД!!» чтобы сообщить игрокам,что теперь они могут нажать свою кнопку,чтобы выиграть.
- Присоедините к документу прослушиватель событий
keydown
.При нажатии любой кнопки запускается функцияkeyHandler()
. - Внутри
keyHandler()
код включает объект события в качестве параметра(представленныйe
)-его свойствоkey
содержит только что нажатую клавишу,и вы можете использовать это для ответа на определенные нажатия клавиш с помощью конкретные действия. - Установите для переменной
isOver
значение false,чтобы мы могли отслеживать,были ли нажаты правильные клавиши для выигрыша игрока 1 или 2.Мы не хотим,чтобы игра заканчивалась при нажатии неправильной клавиши. - Зарегистрируйте
e.key
в консоли,что является полезным способом определения значенияkey
различных клавиш,которые вы нажимаете. - Если
e.key
имеет значение «a»,отобразить сообщение о том,что выиграл Игрок 1,а когдаe.key
-«l»,отобразить сообщение о том,что Игрок 2 выиграл.(Примечание:Это будет работать только со строчными буквами a и l-если переданы прописные буквы A или L(клавиша плюсShift),это считается другой клавишей!)Если была нажата одна из этих клавиш,установитебольше
доистинно
. - Только если
isOver
равноtrue
,удалите прослушиватель событийkeydown
с помощьюremoveEventListener()
,чтобы после того,как произошло выигрышное нажатие,ввод с клавиатуры больше не мог испортить окончательный результат игры.Вы также используетеsetTimeout()
для вызоваreset()
через 5 секунд-как объяснялось ранее,эта функция сбрасывает игру обратно в исходное состояние,чтобы можно было начать новую игру.
Вот и все-готово!
Вот и все-все основы асинхронных циклов и интервалов рассмотрены в одной статье.Вы найдете эти методы полезными во многих ситуациях,но не злоупотребляйте ими!Поскольку они по-прежнему выполняются в основном потоке,тяжелые и интенсивные обратные вызовы(особенно те,которые управляют DOM)могут действительно замедлить страницу,если вы не будете осторожны.
Работа с таймерами в Node.js
Таймеры-это полиглоты.Они очень полезны во многих случаях использования.Их поддерживают почти все основные языки программирования,и Node.js не исключение.На самом деле в Node это проще,потому что Node позволяет нам повторно использовать наши существующие знания таймеров.
В этом посте я опишу и продемонстрирую,что такое таймеры,как их использовать,как выглядит синтаксис,а затем как вы можете использовать их в своих приложениях.Один из распространенных примеров:если вы хотите получить данные из REST API за определенный интервал,вы можете очень легко добиться этого,используя таймеры.Итак,даже если вы новичок в JavaScript или таймерах,этот пост поможет вам понять эти концепции.Если вам интересно узнать больше о Node,вы также можете проверить другие мои статьи.
Таймеры
Таймеры-очень популярные глобальные функции в браузерахСреда:
Node.js также имеет API для этих функций,и он точно соответствуетAPI браузера.
Эти функции могут использоваться длязадержкиилиповторениявыполнения других функций,которые они получают в качестве аргумента.Примеры таймеров
-setTimeout
Этот код использует
setTimeout
для задержки выполнения функции на 4 секунды.Обратите внимание,что функция,переданная в качестве аргумента,является ссылкой на функцию.Возможно,это не встроенная функция.Вот вариант того же кода,где функция не передается в строку.
На следующем снимке экрана показан другой вариант,показывающий,как передавать аргументы в ссылку на функцию.
Итак,все вышеупомянутые примеры очень просты и демонстрируют вам различные стили настройки функции
setTimeout
.Упражнение с таймерами
Вот вам упражнение.Если хотите,вы можете поделиться своим решением в разделе комментариев.Также,если интересно,дайте мне знать,и я тоже поделюсь своим решением.Итак,вот описание упражнения.
- Распечатайте следующее(после соответствующих задержек):
- «Привет через 4 секунды»
- «Привет,через 8 секунд»
- Ограничения:
- Определите в скрипте только одну функцию,которая включает встроенные функции.Подсказка:это может выглядеть примерно так,как показано ниже(снова используйте для этого свой собственный способ и как хотите).
Примеры таймеров-setInterval
Мы можем использоватьsetInterval,если мы хотим,чтобыповторилкакое-то действие вовремя.Следующий пример будет печатать на консоль через 3 секунды,навсегда(если мы не остановим это).
Отмена таймеров
Еще одна замечательная особенность таймеров-это то,что их можно отменить с помощью кода.напримерclearTimeout(timerId).
Вместо clearTimeout вы можете использоватьSetImmediateдля того же результата.но это встречается реже.
Если вы используетеsetInterval,,вы также можете использовать функциюclearInterval,чтобы отменить это.Следующий пример демонстрирует это.
Сводка
Мы узнали,что работать с таймерами в Node.js.Код аналогичен тому,что мы использовали в JavaScript для браузеров.Это очень удобные функции,которые можно использовать в различных сценариях.Вы уже выполнили упражнение,попробуйте и поделитесь со мной своим решением.Если у вас возникнут вопросы,дайте мне знать.До следующего раза,удачного кодирования.
Другие ссылки
Отчет о ходе выполнения с помощью setInterval
Присоединяйтесь к Alex Banks для подробного обсуждения в этом видео.Отчет о ходе работы с помощью setInterval,части основного обучения Node.js.
Обновлено
02.04.2020
Выпущено
10.05.2019
Узел.js-это мощный инструмент для управления серверами,создания веб-приложений и создания программ,управляемых событиями.И он берет из браузера JavaScript-язык,знакомый всем веб-разработчикам.С помощью Node.js вы можете создавать приложения,которые работают на вашем ноутбуке или даже в облаке.В этом курсе вы узнаете основы Node.js и начнете создавать свои собственные приложения JavaScript.Инструктор Алекс Бэнкс знакомит вас со всеми основами,показывая,как установить Node.js и работать с ядром Node.js,которое включает стандартный ввод,стандартный вывод,модульную систему,файловую систему,а также как писать и запускать JavaScript.на сервере.По завершении этого курса вы будете вооружены фундаментальными концепциями и методами Node.js,которые сможете использовать в своем следующем проекте.
Темы включают:
- Что такое Node.js?
- Установка Node.js
- Глобальный объект
- Импорт основных модулей
- Создание пользовательских событий с помощью EventEmitter
- Чтение,запись и удаление файлов
- Работа с файловыми потоками
- Создание дочерних процессов с помощью функций exec и spawn
Уровень квалификации
Средний
1ч 53м
Продолжительность
139 573
Просмотры
Показать больше
Показывай меньшеПродолжить оценку
Вы начали это тестирование ранее,но не прошли его.Вы можете продолжить с того места,где остановились,или начать заново.
Продолжить
Начать сначала.
[an error occurred while processing the directive] [an error occurred while processing the directive]