Функцияны учурда эмес, кийинчерээк, белгиленген убакыт аралыгынан кийин чакыра алабыз. Бул "чалууларды пландаштыруу" деп аталат.
Бул үчүн эки ыкма бар:
setTimeout
белгилүү бир убакыт аралыгынан кийин функцияны бир жолу чакырууга мүмкүндүк берет.setInterval
белгилүү бир убакыт аралыгы өткөндөн кийин чалууну кайталап, функцияны үзгүлтүксүз чакырууга мүмкүндүк берет.
Бул ыкмалар JavaScript спецификациясынын бир бөлүгү эмес. Бирок көпчүлүк JS кодунун иштөө убактысында ички пландоочу бар жана бул ыкмаларга мүмкүнчүлүк берет. Атап айтканда, алар бардык браузерлерде жана Node.js колдоого алынат.
setTimeout
Синтаксис:
@A@let timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...);@A@
Параметрлер:
func|code
Аткарылуучу функция же код сапы. Адатта, бул функция. Тарыхый себептерден улам, сиз коддун сабын да өткөрө аласыз, бирок бул сунушталбайт.
delay
Миллисекунддор менен башталганга чейин кечигүү (1000мс = 1сек). Демейки маани - 0.
arg1
, arg2
…
Аргументтер функцияга өттү
Мисалы, бул код sayHi()
бир секунддан кийин чакырат:
@A@function sayHi() {
alert('Привет');
}
setTimeout(sayHi, 1000);@A@
Аргументтер менен:
@A@function sayHi(phrase, who) {
alert( phrase + ', ' + who );
}
setTimeout(sayHi, 1000, "Привет", "Джон"); // Привет, Джон@A@
Эгерде биринчи аргумент сап болсо, анда JavaScript андан функцияны түзөт.
Бул да иштейт:
@A2setTimeout("alert('Привет')", 1000);@A@
Бирок саптарды колдонуу сунушталбайт. Анын ордуна функцияларды колдонуңуз. Мисалы, бул сыяктуу:
@A@setTimeout(() => alert('Привет'), 1000);@A@
()
Жаңы баштаган иштеп чыгуучулар кээде функциядан кийин кашааларды кошуп ката кетиришет :
@A@// неправильно!
setTimeout(sayHi(), 1000);@A@
Бул иштебейт, анткени setTimeout
ал функция шилтемесин күтөт. Бул жерде sayHi()
функциянын аткарылышы башталат жана аткаруунун натыйжасы жөнөтүлөт setTimeout
. Биздин учурда, аткаруу натыйжасы sayHi()
болуп саналат undefined
(анткени функция эч нерсе кайтарбайт), ошондуктан эч нерсе пландаштырылбайт.
clearTimeout аркылуу жокко чыгаруу
Чалуу setTimeout
"таймер идентификаторун" кайтарат timerId
, аны андан ары аткарууну жокко чыгаруу үчүн колдонсо болот.
жокко чыгаруу үчүн синтаксиси:
@Alet timerId = setTimeout(...);
clearTimeout(timerId);@A@
Төмөнкү коддо биз функцияны чакырууну пландаштырып, андан кийин аны жокко чыгарабыз (биз жөн гана оюбузду өзгөрттүк). Натыйжада, эч нерсе болбойт:
@A@let timerId = setTimeout(() => alert("ничего не происходит"), 1000);
alert(timerId); // идентификатор таймера
clearTimeout(timerId);
alert(timerId); // тот же идентификатор (не принимает значение null после отмены)@A@
Чыгуудан көрүнүп тургандай alert
, браузерде таймер идентификатору сан болуп саналат. Башка чөйрөлөрдө, бул башка нерсе болушу мүмкүн. Мисалы, Node.js кошумча ыкмалар менен таймер объектисин кайтарат.
Дагы бир жолу, бул ыкмалар үчүн бирдиктүү спецификация жок, ошондуктан бул жүрүм-турум нормалдуу.
Браузерлер үчүн таймерлер HTML5 стандартынын Таймерлер бөлүмүндө сүрөттөлөт .
setInterval
Метод setInterval
төмөнкүдөй синтаксиске ээ setTimeout
:
@A@let timerId = setInterval(func|code, [delay], [arg1], [arg2], ...);@A@
Бардык аргументтер бирдей мааниге ээ. Бирок бул ыкманын ортосундагы айырмачылык setTimeout
функция бир жолу эмес, мезгил-мезгили менен белгиленген убакыт аралыгы өткөндөн кийин иштетилет.
Функциянын андан ары аткарылышын токтотуу үчүн, сиз чалышыңыз керек clearInterval(timerId)
.
Төмөнкү мисал ар бир 2 секундада билдирүү басып чыгарат. 5 секунддан кийин чыгаруу токтойт:
@A@// повторить с интервалом 2 секунды
let timerId = setInterval(() => alert('tick'), 2000);
// остановить вывод через 5 секунд
setTimeout(() => { clearInterval(timerId); alert('stop'); }, 5000);@A@
alert
убакыт да өтөтКөпчүлүк браузерлерде, анын ичинде Chrome жана Firefox, ички эсептегич alert/confirm/prompt
.
Демек, эгер сиз жогорудагы кодду иштетип, alert
жабуу үчүн бир нече секунд күтсөңүз, кийинкиси alert
мурункуну жапканда дароо көрсөтүлөт. Билдирүүлөрдүн ортосундагы убакыт аралыгы alert
2 секунддан азыраак болот.
Уюшкан setTimeout
Бир нерсени үзгүлтүксүз иштетүүнүн эки жолу бар.
Алардын бири setInterval
. Экинчиси уя салынган setTimeout
. Мисалы:
@A@/** вместо:
let timerId = setInterval(() => alert('tick'), 2000);
*/
let timerId = setTimeout(function tick() {
alert('tick');
timerId = setTimeout(tick, 2000); // (*)
}, 2000);@A@
Жогорудагы ыкма setTimeout
кийинки чалууну учурдагы чалуу аяктагандан кийин пландаштырат (*)
.
Nested setTimeout
караганда ийкемдүү setInterval
. Анын жардамы менен кийинки чалуу мурункусунун жыйынтыгына жараша башкача коюлушу мүмкүн.
Мисалы, ар бир 5 секунд сайын серверге маалыматтарды алуу өтүнүчүн жөнөтүүчү кызматты жазуу керек, бирок сервер ашыкча жүктөлсө, анда суроо-талап аралыгын 10, 20, 40 секундга чейин көбөйтүү керек ... Бул жерде псевдокод:
@A@let delay = 5000;
let timerId = setTimeout(function request() {
...отправить запрос...
if (ошибка запроса из-за перегрузки сервера) {
// увеличить интервал для следующего запроса
delay *= 2;
}
timerId = setTimeout(request, delay);
}, delay);@A@
Ал эми биз пландаштырып жаткан функциялар ресурстарды көп талап кылса жана убакытты талап кылса, анда биз эртеби-кечпи кийинки чалууну аткарууга жана пландаштырууга кеткен убакытты өлчөй алабыз.
Nested setTimeout
аткаруунун ортосундагы кечиктирүүнү -га караганда так коюуга мүмкүндүк берет setInterval
.
Келгиле, эки код үзүндүсүн салыштырып көрөлү. Биринчиси колдонот setInterval
:
@A@let i = 1;
setInterval(function() {
func(i);
}, 100);
Экинчиси уячаны колдонот setTimeout
:
let i = 1;
setTimeout(function run() {
func(i);
setTimeout(run, 100);
}, 100);@A@
Ички пландоочу үчүн ал ар 100 мс setInterval
аткарат :func(i)
Көңүл бурдуңузбу?
func
Чалуулардын ортосундагы чыныгы кечигүү setInterval
коддо көрсөтүлгөндөн азыраак!
Бул нормалдуу, анткени аткарууга кеткен убакыт func
берилген убакыт аралыгынын бир бөлүгүн колдонот.
func
Аткаруу биз күткөндөн узунураак болуп, 100 мсден ашык убакытты талап кылышы мүмкүн .
Бул учурда, кыймылдаткыч аткаруунун бүтүшүн күтүп func
, андан кийин пландаштыргычты текшерет жана убакыт өтүп кетсе, аны дароо кайра иштетет.
Экстремалдуу учурда, функция ар дайым кечиктирүүдөн узагыраак иштесе delay
, анда чалуулар эч кандай кечиктирбестен иштейт.
Төмөндө рекурсивдүү процессти көрсөткөн сүрөт setTimeout
:
Nested setTimeout
белгиленген кечиктирүүгө кепилдик берет (бул жерде 100 мс).
Себеби, жаңы чалуу мурунку чалуунун аягында пландаштырылган.
Функцияга өткөндө setInterval/setTimeout
, ал ички шилтемеге алынат жана пландаштыргычта сакталат. Бул функциянын таштанды жыйгычка кирүүсүнө жол бербейт, атүгүл ага башка шилтемелер жок.
@A@// функция остаётся в памяти до тех пор, пока планировщик обращается к ней
setTimeout(function() {...}, 100);@A@
for setInterval
функциясы чакырылганга чейин эс тутумда кала берет clearInterval
.
Ошондой эле терс таасири бар. Функция сырткы лексикалык чөйрөнү билдирет, ошондуктан ал бар болсо да, сырткы өзгөрмөлөр да бар. Алар функциянын өзүнө караганда көбүрөөк эстутумду ээлей алышат. Ошондуктан, эгерде кадимки функцияны чакыруунун кереги жок болсо, анда функция өтө кичинекей болсо да, аны жокко чыгарган жакшы.
нөл кечигүү менен setTimeout
Өзгөчө колдонуу учуру: setTimeout(func, 0)
же жөн гана setTimeout(func)
.
Бул чалууну func
мүмкүн болушунча тез пландаштырат. Бирок пландоочу функцияны учурдагы код аткарылып бүткөндө гана чакырат.
Ошентип, функцияны чакыруу учурдагы код аткарылгандан кийин дароо пландаштырылат.
Мисалы, бул код "Салам", анан дароо "Дүйнө" басып чыгарат:
@A@setTimeout(() => alert("Мир"));
alert("Привет");@A@
Биринчи сап чалууну 0мс кийин "календарга" коёт. Бирок пландоочу "календарды" учурдагы код аяктагандан кийин гана текшерет. Ошондуктан, "Привет"
ал биринчи көрсөтүлөт, жана "Мир"
- андан кийин.
Браузерлерде нөлдүк күтүү үчүн колдонуунун өркүндөтүлгөн учурлары бар, биз аларды Окуялардын цикли: Микроталаптар жана Макроталаптар бөлүмүндө карайбыз .
Браузерде ички эсептегичтердин канча жолу аткарыла турганына чектөө коюлган. HTML5 стандарты мындай дейт: "Беш уячаланган таймерден кийин интервал жок дегенде төрт миллисекунд болушу керек."
Бул эмнени билдирерин төмөндөгү мисалда көрсөтөлү. Чалуу setTimeout
0 мсден кийин өзүн кайра чакырат. Ар бир чалуу массивдеги мурунку чалуудан реалдуу убакытты эстейт times
. Чыныгы кечигүү деген эмне? карап көрөлү:
@A@let start = Date.now();
let times = [];
setTimeout(function run() {
times.push(Date.now() - start); // запоминаем задержку от предыдущего вызова
if (start + 100 < Date.now()) alert(times); // показываем задержку через 100 мс
else setTimeout(run); // если нужно ещё запланировать
});
// пример вывода:
// 1,1,1,1,9,15,20,24,30,35,40,45,50,55,59,64,70,75,80,85,90,95,100@A@
Биринчи таймер дароо башталат (спецификацияда көрсөтүлгөндөй), андан кийин кечигүү ишке кирет жана биз көрөбүз 9, 15, 20, 24...
.
setInterval
Ушундай эле нерсе : ордуна колдонулганда болот setTimeout
: нөлдүк кечигүү менен бир нече жолу setInterval(f)
иштейт f
, андан кийин 4+ мс кечигүү менен.
Бул чектөө көптөн бери бар, көптөгөн сценарийлер ага таянат, ошондуктан ал тарыхый себептерден улам сакталып келет.
Бул чектөө сервер тараптагы JavaScript'те жок. Ал жерде асинхрондук тапшырмаларды пландаштыруунун башка жолдору бар. Мисалы, Node.js үчүн setImmediate . Демек, бул чектөө браузерлерге гана тиешелүү.
Бардыгы
setInterval(func, delay, ...args)
жана ыкмалары үзгүлтүксүз же мс-де көрсөтүлгөн кечигүүдөн кийин бир гана жолуsetTimeout(func, delay, ...args)
аткарууга мүмкүндүк берет .func
delay
- Аткаруудан баш тартуу үчүн, сиз
clearInterval/clearTimeout
кайтарган маани менен чалышыңыз керекsetInterval/setTimeout
. - Ички чалуу
setTimeout
ийкемдүү альтернатива болуп саналатsetInterval
. Ал ошондой эле аткаруунун ортосундагы интервалды так коюуга мүмкүндүк берет. - Нөлдүк кечиктирүү пландаштыруу
setTimeout(func,0)
же ага окшош,setTimeout(func)
учурдагы код аткарылып бүткөндөн кийин мүмкүн болушунча тез арада аткарылышы керек болгон чалуулар үчүн колдонулат. - Браузер беш же андан ашык чалуулардын ортосундагы минималдуу кечиктирүүнү 4 мс
setTimeout
жанаsetInterval
5-чакыруудан баштап чектейт.
Бардык пландаштыруу ыкмалары так кечиктирүүгө кепилдик бербей турганын эске алыңыз.
Мисалы, браузердин таймери көптөгөн себептерден улам жайлатышы мүмкүн:
- Процессор ашыкча жүктөлгөн.
- Фондо серепчи өтмөгү.
- Ноутбуктун батареясынын иштеши.
Мунун баары таймердин минималдуу аралыгын (жана минималдуу кечиктирүүнү) серепчиге жана ОСтун иштөө жөндөөлөрүнө жараша 300, ал тургай 1000 мс чейин көбөйтө алат.
Tasks
printNumbers(from, to)
Санды секунд сайын баштап from
жана менен аяктаган функцияны жазыңыз to
.
Эки чечимди жасаңыз.
- колдонуу
setInterval
. - Рекурсивдүү колдонуу
setTimeout
.
Төмөнкү коддо чалуу пландаштырылган setTimeout
, андан кийин 100 мсден ашык убакытты талап кылган татаал эсептөө жүргүзүлөт.
Пландаштырылган функция качан бүтөт?
- циклден кийин.
- цикл алдында.
- Циклдин башында.
Эмне көрсөтөт alert
?
@A@let i = 0;
setTimeout(() => alert(i), 100); // ?
// предположим, что время выполнения этой функции >100 мс
for(let j = 0; j < 100000000; j++) {
i++;
}@A@