Počítače Okna Internet

Časovače v Javascriptu (setInterval, setTimeout). Příklady funkce jQuery setTimeout () Javascript zabraňuje spuštění více časovačů setinterval současně

Časový limit JavaScriptu je nativní funkce JavaScriptu, která spustí část kódu po zadaném časovém zpoždění (v milisekundách). To se může hodit, když potřebujete zobrazit vyskakovací okno poté, co uživatel strávil nějaký čas na vaší stránce. Nebo chcete, aby efekt začal, když najedete kurzorem na prvek až po nějaké době. Tímto způsobem se můžete vyhnout neúmyslnému spuštění efektu, pokud uživatel náhodně přejede kurzorem.

Jednoduchý příklad setTimeout

Abychom demonstrovali účinek této funkce, doporučuji podívat se na následující ukázku, ve které se dvě sekundy po kliknutí na tlačítko objeví vyskakovací okno.

Zobrazit demo

Syntax

Dokumentace MDN poskytuje následující syntaxi pro setTimeout:

var timeoutID = window.setTimeout (func,); var timeoutID = window.setTimeout (kód,);

  • timeoutID je číselné id, které lze použít ve spojení s clearTimeout () k deaktivaci časovače;
  • func je funkce, která má být provedena;
  • kód ( v alternativní syntaxi) - řádek kódu, který se má provést;
  • zpoždění - doba zpoždění v milisekundách, po které funkce poběží. Výchozí hodnota je 0.

setTimeout vs window.setTimeout

Výše uvedená syntaxe používá window.setTimeout. Proč?

SetTimeout a window.setTimeout jsou ve skutečnosti prakticky stejné funkce. Jediný rozdíl je v tom, že ve druhém výrazu používáme metodu setTimeout jako vlastnost objektu globálního okna.

Osobně si myslím, že to kód jen hodně komplikuje. Pokud bychom měli definovat alternativní metodu časového limitu JavaScriptu, kterou lze najít a vrátit v pořadí podle priority, narazili bychom na ještě větší problémy.

V tomto tutoriálu se nechci zahrávat s objektem okna, ale obecně je na vás, kterou syntaxi použijete.

Příklady použití

Může to být název funkce:

funkce explode () (upozornění ("Boom!");) setTimeout (explode, 2000);

Proměnná, která odkazuje na funkci:

var explode = funkce () (upozornění ("Boom!");); setTimeout (explode, 2000);

Nebo anonymní funkce:

setTimeout (funkce () (upozornění ("Boom!");), 2000);

  • Takový kód je špatně vnímán, a proto bude obtížné jej modernizovat nebo ladit;
  • Zahrnuje použití metody eval (), která by mohla představovat potenciální zranitelnost;
  • Tato metoda je pomalejší než ostatní, protože musí běžet Překladač JavaScriptu.

Upozorňujeme také, že k testování kódu používáme metodu upozornění na časový limit JavaScriptu.

Předání parametrů do setTimout

Zaprvé ( kromě toho cross-browser) variantě předáme parametry funkci zpětného volání provedené s setTimeout.

V následujícím příkladu extrahujeme náhodný pozdrav z pole pozdravů a ​​předáme jej jako parametr funkci pozdravu (), kterou provede setTimeout se zpožděním 1 sekundy:

function greet (pozdrav) (console.log (zdraví);) function getRandom (arr) (return arr;) var greetings = ["Ahoj", "Bonjour", "Guten Tag"], randomGreeting = getRandom (zdraví); setTimeout (funkce () (pozdravit (randomGreeting);), 1000);

Zobrazit demo

Alternativní metoda

V syntaxi na začátku tohoto článku je další metoda, kterou lze použít k předání parametrů funkci zpětného volání spuštěné časovým limitem JavaScriptu. Tato metoda předpokládá výstup všech parametrů po zpoždění.

Na základě předchozího příkladu dostaneme:

setTimeout (pozdrav, 1000, náhodný pozdrav);

Tato metoda nebude fungovat v IE 9 a nižších, kde jsou předávané parametry nedefinované. Ale k vyřešení tohoto problému na MDN má speciální polyfill.

Související problémy a "toto"

Kód spuštěný setTimeout běží odděleně od funkce, která jej volala. Z tohoto důvodu se potýkáme s určitými problémy, jako řešení lze použít klíčové slovo this.

var person = (firstName: "Jim", úvod: function () (console.log ("Ahoj, já" m "+ this.firstName);)); person.introduce (); // Výstupy: Ahoj, já" m Jim setTimeout (person.introduce, 50); // Výstupy: Ahoj, nejsem definován

Důvod tohoto závěru spočívá ve skutečnosti, že v prvním příkladu to vede k objektu osoba a ve druhém příkladu ukazuje na objekt globálního okna, který nemá vlastnost firstName.

Chcete-li se této nekonzistence zbavit, můžete použít několik metod:

Vynutit nastavení

To lze provést pomocí bind (), metody, která vytvoří novou funkci, která, když je volána jako hodnota klíče this, používá konkrétní hodnotu. V našem případě objekt zadané osoby. To nám ve výsledku dává:

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

Poznámka: Metoda vazby byla zavedena v ECMAScript 5, což znamená, že bude fungovat pouze v moderních prohlížečích. V jiných se při použití zobrazí chyba za běhu JavaScript "chyba vypršení časového limitu".

Použijte knihovnu

Mnoho knihoven obsahuje vestavěné funkce potřebné k vyřešení tohoto problému. Například metoda jQuery.proxy (). Vezme funkci a vrátí novou, ve které bude vždy používat konkrétní kontext. V našem případě bude kontext:

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

Zobrazit demo

Zakázat časovač

Vrácená hodnota setTimeout je číselné ID, které lze použít k deaktivaci časovače pomocí funkce clearTimeout ():

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

Podívejme se na to v akci. Pokud v dalším příkladu kliknete na tlačítko " Spusťte odpočítávání“, Spustí se odpočítávání. Po jeho skončení dostanou své koťata. Ale když stisknete tlačítko " Zastavit odpočítávání“, Časový limit JavaScriptu bude zastaven a resetován.

Zobrazit příklad

Pojďme si to shrnout

setTimeout je asynchronní funkce, což znamená, že přijaté volání této funkce je zařazeno do fronty a bude provedeno až po dokončení všech ostatních akcí na zásobníku. Nemůže běžet současně s jinými funkcemi nebo samostatným vláknem.

Je nesmírně důležité pochopit, jak fungují časovače JavaScriptu. Jejich chování často neodpovídá našemu intuitivnímu vnímání multithreadingu a je to dáno tím, že vlastně běží na stejném vláknu. Pojďme se podívat na čtyři funkce, pomocí kterých můžeme ovládat časovače:

  • var id = setTimeout (fn, zpoždění); - Vytvoří jednoduchý časovač, který zavolá zadanou funkci po zadané prodlevě. Funkce vrací jedinečné ID, pomocí kterého lze časovač pozastavit.
  • var id = setInterval (fn, zpoždění); - Podobné jako setTimeout, ale neustále volá funkci v zadaném intervalu (dokud se nezastaví).
  • clearInterval (id) ;, clearTimeout (id); - Přijímá ID časovače (vrácené jednou z funkcí popsaných výše) a zastaví provádění zpětného volání "a.
Hlavní myšlenkou, kterou je třeba vzít v úvahu, je, že není zaručena přesnost doby zpoždění časovače. Pro začátek provede prohlížeč všechny asynchronní události JavaScriptu ve stejném vláknu (jako jsou kliknutí myší nebo časovače) a pouze tehdy, když je událost na řadě. Nejlépe to ilustruje následující schéma:

Na tomto obrázku je mnoho informací, které je třeba pochopit, ale pochopení vám poskytne hlubší pochopení toho, jak funguje asynchronní provádění JavaScriptu. Tento diagram svisle představuje čas v milisekundách a modré bloky představují bloky kódu JavaScript, který byl spuštěn. Například první blok je proveden v průměru za 18 ms, kliknutí myší blokuje provedení na přibližně 11 ms atd.

JavaScript může spustit pouze jeden blok kódu (kvůli jednovláknové povaze provádění), z nichž každý blokuje provádění jiných asynchronních událostí. To znamená, že když dojde k asynchronní události (jako je kliknutí myší, volání časovače nebo dokončení požadavku XMLHttp), je přidána do fronty a spuštěna později (implementace se samozřejmě liší v závislosti na prohlížeči, ale domluvme se, že tomu budeme říkat "fronta") ...

Pro začátek si představme, že uvnitř bloku JavaScriptu začínají dva časovače: setTimeout se zpožděním 10 ms a setInterval se stejným zpožděním. V závislosti na tom, kdy se časovač spustí, se spustí v okamžiku, kdy jsme ještě nedokončili první blok kódu. Všimněte si však, že se nespustí hned (není možné kvůli single-threadingu). Místo toho je odložená funkce zařazena do fronty a spuštěna v příštím dostupném čase.

Během provádění prvního bloku JavaScriptu také dojde ke kliknutí myší. Obslužnou rutinu této asynchronní události (a ta je asynchronní, protože ji nemůžeme předvídat) nelze v tuto chvíli provést přímo, takže se také zařadí do fronty, stejně jako časovač.

Po provedení prvního bloku kódu JavaScript se prohlížeč zeptá na otázku "Co čeká na spuštění?" V tomto případě jsou ovladač kliknutí myší a časovač ve stavu čekající na vyřízení. Prohlížeč vybere jeden z nich (obslužný program kliknutí) a spustí jej. Časovač bude čekat na další dostupný čas ve frontě provádění.

Všimněte si, že zatímco se provádí obslužná rutina kliknutí myší, spustí se první intervalové zpětné volání. Stejně jako zpětné volání časovače bude zařazen do fronty. Pamatujte však, že když se interval znovu spustí (během zpětného volání časovače), bude odstraněn z fronty. Pokud by všechna intervalová zpětná volání "byla zařazena do fronty během provádění velkého kusu kódu, vedlo by to k množství funkcí čekajících na volání bez zpoždění mezi jejich dokončením. Místo toho mají prohlížeče tendenci čekat, dokud nezůstanou žádné funkce. fronty před přidáním dalšího do fronty.

Můžeme tedy pozorovat případ, kdy se třetí aktivace intervalového zpětného volání shoduje s okamžikem, kdy se již provádí. To ilustruje důležitý bod: intervaly se nestarají o to, co právě běží, budou přidány do fronty bez ohledu na prodlevu mezi provedeními.

Nakonec, po dokončení druhého intervalového zpětného volání, vidíme, že už nezbývá nic, co by JavaScriptový engine mohl provést. To znamená, že prohlížeč opět čeká na nové asynchronní události. K tomu dojde po 50 ms, kdy se znovu spustí intervalové zpětné volání. V tuto chvíli už to nebude nic blokovat, takže to bude fungovat okamžitě.

Podívejme se na příklad, který dobře ilustruje rozdíl mezi setTimeout a setInterval.
setTimeout (funkce () (/ * Nějaký dlouhý blok kódu ... * / setTimeout (arguments.callee, 10);), 10); setInterval (funkce () (/ * Nějaký dlouhý blok kódu ... * /), 10);
Tyto dvě možnosti jsou na první pohled rovnocenné, ale ve skutečnosti nejsou. Kód používající setTimeout bude mít vždy zpoždění alespoň 10 ms po předchozím volání (může to být více, ale nikdy to nemůže být méně), zatímco kód používající setInterval bude mít tendenci volat každých 10 ms bez ohledu na to, kdy bylo předchozí volání provedeno.

Shrňme si výše uvedené:
- JavaScript engine používá jednovláknové prostředí, které transformuje asynchronní události na frontu čekající na spuštění,
- Funkce setTimeout a setInterval se v asynchronním kódu provádějí zásadně odlišnými způsoby,
- Pokud nelze časovač v tuto chvíli spustit, bude odložen do dalšího bodu spuštění (který bude delší než požadované zpoždění),
- Intervaly (setInterval) lze provádět jeden po druhém bez zpoždění, pokud jejich provádění trvá déle než zadaná prodleva.

To vše jsou nesmírně důležité informace pro vývoj. Znalost toho, jak funguje JavaScript engine, zvláště se spoustou asynchronních událostí (což se často stává), pokládá vynikající základ pro vytváření pokročilých aplikací.

  • Z:
  • Registrovaný: 2014.07.08
  • Příspěvky: 3,896
  • Líbí se: 497

Téma: SetTimeOut a SetInterval, co je lepší použít v JavaScriptu?

Chcete-li kód spustit vícekrát v pravidelných intervalech, použijte funkci nastavitInterval... Má však řadu nevýhod, hlavně odlišné chování v různých prohlížečích.

Prvním rozdílem je rozdíl, kdy je časovač nastaven na další start. Vytvořme si malý test: změříme množství času, které uplynulo od začátku předchozího běhu a od jeho konce.

var d1 = nové datum (), d2 = nové datum (); setInterval (funkce () (var d = nové datum (); document.body.innerHTML + = (d - d1) + "" + (d - d2) + "
"; // Umístěte popisek na začátek funkce d1 = new Date (); while (new Date () - d1< 200); // ничего не делаем 200 миллисекунд // И в конце функции d2 = new Date(); }, 1000);

Výstup bude informativní od druhého řádku.

Ve Firefoxu, Opeře, Safari a Chrome bude situace podobná: první číslo bude přibližně 1 000, druhé - o 200 méně. Rozdíl bude pouze v rozmezí hodnot. Nejmenší variace v Chrome a Opeře.

2 Odpovědět od PunBB (upraveno PunBB 2017.06.08 16:45)

  • Z: Moskva, Sovchoznay 3, apt. 98
  • Registrovaný: 2014.07.08
  • Příspěvky: 3,896
  • Líbí se: 497

Dalším rozdílem, který je méně patrný a obtížněji reprodukovatelný, ale někdy může způsobit velké potíže, je odolnost vůči změnám v systémovém čase. Pokud spustíte další test

setInterval (funkce () (document.body.innerHTML = Math.random ();), 500);

A po spuštění nastavit systémový čas o minutu zpět, v prohlížečích Firefox a Safari se pak změna čísel pozastaví a po minutě se spustí znovu. Ruční překlad systémového času je samozřejmě extrémně vzácná situace, ale mnoho systémů je nakonfigurováno tak, aby automaticky synchronizovaly čas se servery na internetu, takže v některých situacích nelze tento faktor ignorovat.

Další drobnou nevýhodou funkce setInterval je, že abyste mohli zastavit její činnost, musíte si někde zapamatovat její identifikátor, což se ne vždy hodí.

3 Odpovědět od PunBB

  • Z: Moskva, Sovchoznay 3, apt. 98
  • Registrovaný: 2014.07.08
  • Příspěvky: 3,896
  • Líbí se: 497

Re: SetTimeOut a SetInterval, co je lepší použít v JavaScriptu?

Chcete-li se zbavit uvedených nevýhod setInterval, můžete použít více setTimeout.

Důležitou alternativou k setInterval je rekurzivní setTimeout:

/ ** místo: var timerId = setInterval (funkce () (upozornění ("tick");), 2000); * / var timerId = setTimeout (funkce tick () (upozornění ("tick"); timerId = setTimeout (tick, 2000);), 2000);

Ve výše uvedeném kódu je další spuštění naplánováno bezprostředně po předchozím.

Rekurzivní setTimeout je flexibilnější metoda časování než setInterval, protože čas do dalšího spuštění lze naplánovat odlišně v závislosti na výsledcích toho aktuálního.

Máme například službu, která každých 5 sekund dotazuje server na nová data. Pokud je server přetížený, můžete zvýšit interval dotazování na 10, 20, 60 sekund... A pak jej vrátit zpět, až bude vše normalizováno.

Pokud máme pravidelně úkoly, které zatěžují procesor, pak můžeme odhadnout čas strávený jejich prováděním a naplánovat další spuštění dříve nebo později.

4 Odpovědět od PunBB

  • Z: Moskva, Sovchoznay 3, apt. 98
  • Registrovaný: 2014.07.08
  • Příspěvky: 3,896
  • Líbí se: 497

Re: SetTimeOut a SetInterval, co je lepší použít v JavaScriptu?

Rekurzivní setTimeout zaručuje pauzu mezi hovory, setInterval nikoli.

Porovnejme oba kódy. První používá setInterval:

var i = 1; setInterval (funkce () (funkce (i);), 100);

Druhý používá rekurzivní setTimeout:

var i = 1; setTimeout (funkce run () (func (i); setTimeout (run, 100);), 100);

S setInterval se interní časovač spustí přesně každých 100 ms a zavolá funkci (i):

Skutečná pauza mezi voláním funkce setInterval je menší, než je uvedeno v kódu!

Je to přirozené, protože provozní doba funkce není nijak zohledněna, část intervalu „sežere“.

Je také možné, že se funkce func ukázala být složitější, než jsme očekávali, a její provedení trvalo déle než 100 ms.

V tomto případě tlumočník počká na dokončení funkce, poté zkontroluje časovač, a pokud čas pro volání setInterval již nastal (nebo uplynul), další volání proběhne okamžitě.

Pokud funkce trvá déle než pauza setInterval, pak volání proběhnou bez přerušení.

5 Odpovědět od sempai

  • Z: Jeruzalém
  • Registrovaný: 2015.06.02
  • Příspěvky: 958
  • Líbí se: 274

Re: SetTimeOut a SetInterval, co je lepší použít v JavaScriptu?

Vše závisí na aktuálním úkolu. Zpočátku se SetTimeOut používá k jednorázovému spuštění časovače a SetInterval ke spuštění smyčky. Ale obě funkce lze použít k procházení skriptů, pokud například poběží rekurzivně ve funkci SetTimeOut, bude se chovat prakticky podobně jako SetInterval.

Nevýhodou SetIntervalu v tuto chvíli je, že nezohledňuje dobu provádění samotného skriptu (funkce) a pokud jej například používáte pro těžké požadavky, pak se doba intervalu výrazně zkrátí a se může v různých prohlížečích lišit.

Ale znovu opakuji, pokud je funkce nebo požadavek minimalizován, pak koncový uživatel pravděpodobně nepocítí rozdíl.
Proto, co použít, každý rozhodne sám za sebe.

Zdroj: http://learn.javascript.ru/settimeout-setinterval

Téměř všechny implementace JavaScriptu mají interní časovač plánování, který vám umožňuje naplánovat volání funkce po určité době.

Tato funkce je podporována zejména v prohlížečích a na serveru Node.JS.

setTimeout

Syntax:

var timerId = setTimeout (funkce / kód, zpoždění [, arg1, arg2 ...])

Možnosti:

  • funkce / kód
    • Funkce nebo řádek kódu, který se má provést.
    • Řetězec je podporován z důvodu kompatibility a nedoporučuje se.
  • zpoždění
    • Zpoždění v milisekundách, 1000 milisekund se rovná 1 sekundě.
  • arg1, arg2...
    • Argumenty k předání funkci. Není podporováno v IE9-.
    • Funkce bude vykonána po čase zadaném v parametru delay.

Například následující kód zavolá upozornění („Ahoj“) po jedné sekundě:

funkce func ()(upozornění ("Ahoj");) setTimeout (func, 1000);

Pokud je prvním argumentem řetězec, interpret z tohoto řetězce vytvoří anonymní funkci.

To znamená, že takový záznam funguje úplně stejným způsobem:

SetTimeout ("upozornění (" Ahoj ")", 1000);

Místo toho použijte anonymní funkce:

SetTimeout ( funkce ()(upozornění ("Dobrý den")), 1000);

Funkční parametry a kontext

Ve všech moderních prohlížečích, s ohledem na IE10, vám setTimeout umožňuje zadat parametry funkcí.

Níže uvedený příklad zobrazí „Ahoj, já jsem Vasya“ všude kromě IE9-:

funkce sayHi (kdo)(upozornění ("Ahoj, já jsem" + kdo);) setTimeout (sayHi, 1000, "Vasya");

... Ve většině případů však potřebujeme podporu pro starý IE a ten vám neumožňuje specifikovat argumenty. Proto, aby je bylo možné předat, je volání zabaleno do anonymní funkce:

funkce sayHi (kdo)(upozornění ("Ahoj, já" + kdo);) setTimeout ( funkce ()(sayHi ("Vasya")), 1000);

Volání přes setTimeout neprojde tímto kontextem.

Zejména volání metody objektu přes setTimeout bude fungovat v globálním kontextu. To může vést k nesprávným výsledkům.

Zavolejte například user.sayHi () po jedné sekundě:

funkce Uživatel (id) funkce ()(upozornění (toto .id);); ) var uživatel = nový uživatel (12345); setTimeout (user.sayHi, 1000); // očekává se 12345, ale vypíše "undefined"

Protože setTimeout spustí funkci user.sayHi v globálním kontextu, nebude moci přes toto přistupovat k objektu.

Jinými slovy, tato dvě volání pro setTimeout dělají totéž:

// (1) jeden řádek setTimeout (user.sayHi, 1000); // (2) totéž na dvou řádcích var func = user.sayHi; setTimeout (func, 1000);

Naštěstí je tento problém také snadno vyřešen vytvořením mezilehlé funkce:

funkce Uživatel (id)(toto .id = id; toto .sayHi = funkce ()(upozornění (toto .id);); ) var uživatel = nový uživatel (12345); setTimeout ( funkce ()(user.sayHi ();), 1000);

Funkce wrapper se používá k předávání argumentů napříč prohlížeči a ukládání kontextu provádění.

Zrušit provedení

Funkce setTimeout vrací timerId, který lze použít ke zrušení akce.

Syntax:

ClearTimeout (timerId)

V následujícím příkladu nastavíme časový limit a poté smažeme (změníme názor). Ve výsledku se nic neděje.

var timerId = setTimeout ( funkce ()(upozornění (1)), 1000); clearTimeout (timerId);

nastavitInterval

Metoda setInterval má syntaxi podobnou setTimeout.

var timerId = setInterval (funkce / kód, zpoždění [, arg1, arg2 ...])

Význam argumentů je stejný. Ale na rozdíl od setTimeout nezahájí provádění funkce jednou, ale pravidelně ji opakuje v určeném časovém intervalu. Provádění můžete zastavit voláním:

ClearInterval (timerId)

V následujícím příkladu se při spuštění zobrazí zpráva každé dvě sekundy, dokud nekliknete na tlačítko Zastavit:

<input type = "button" onclick = "clearInterval (timer)" value = "(! LANG: Stop" > !} <skript> var i = 1; var timer = setInterval ( funkce ()(upozornění (i ++)), 2000);skript>

Řazení a překrývání hovorů v setInterval

Volání setInterval (funkce, zpoždění) nastaví funkci, která se má provést po zadaném časovém intervalu. Ale je tu jemnost.

Ve skutečnosti je pauza mezi hovory kratší než zadaný interval.

Vezměme například setInterval (funkce () (func (i ++)), 100). Provádí funkci func každých 100 ms a pokaždé zvyšuje počítadlo.

Na obrázku níže je červený blok doba provedení funkce func. Doba mezi bloky je doba mezi spuštěním funkce a je menší než nastavené zpoždění!

To znamená, že prohlížeč zahájí spuštění funkce úhledně každých 100 ms, aniž by zohlednil dobu provádění samotné funkce.

Stává se, že provedení funkce trvá déle, než je zpoždění. Například funkce je komplexní a latence je malá. Nebo funkce obsahuje upozornění/potvrzení/výzvy, které blokují spouštěcí vlákno. V tomto případě začínají zajímavé věci.

Pokud funkci nelze spustit, protože je prohlížeč zaneprázdněn, je zařazena do fronty a spuštěna, jakmile je prohlížeč volný.

Obrázek níže ukazuje, co se děje u funkce, jejíž provedení trvá dlouho.

Volání funkce iniciované funkcí setInterval je přidáno do fronty a proběhne okamžitě, jakmile to bude možné:

K druhému spuštění funkce dojde ihned po skončení prvního:

Provedení není zařazeno do fronty více než jednou.

Pokud provedení funkce trvá déle než několik plánovaných provedení, bude stále jednou stát ve frontě. Nedochází tedy k „hromadění“ startů.

Na obrázku níže se setInterval pokusí provést funkci za 200 ms a zařadí volání do fronty. Po 300 ms a 400 ms se časovač znovu probudí, ale nic neproběhne.

Volání setInterval (funkce, zpoždění) nezaručuje skutečnou prodlevu mezi provedeními.

Jsou chvíle, kdy je skutečné zpoždění větší nebo menší než zadané. Obecně není pravda, že dojde alespoň k nějakému zpoždění.

Opakování vnořeného setTimeout

V případech, kdy je potřeba nejen pravidelné opakování, ale je vyžadována prodleva mezi spuštěními, měl by být setTimeout znovu nastaven při každém provedení funkce.

Níže je uveden příklad, který vydává upozornění s intervalem 2 sekund mezi nimi.

<input type = "button" onclick = "clearTimeout (timer)" value = "(! LANG: Stop" > !} <skript> var i = 1; var timer = setTimeout ( spuštění funkce ()(upozornění (i ++); časovač = setTimeout (run, 2000);), 2000);skript>

Mezi spuštěními na časové ose budou pevná zpoždění. Ilustrace pro zpoždění 100 ms:

Minimální zpoždění časovače

Časovač prohlížeče má nejnižší možnou latenci. V moderních prohlížečích se pohybuje od nuly do 4 ms. U starších může být vyšší a dosáhnout 15 ms.

Podle normy je minimální zpoždění 4 ms. Není tedy žádný rozdíl mezi setTimeout (.., 1) a setTimeout (.., 4).

Chování setTimeout a setInterval s nulovou latencí závisí na prohlížeči.

  1. V Opeře je setTimeout (.., 0) stejný jako setTimeout (.., 4). Běží méně často než setTimeout (.., 2). Toto je funkce tohoto prohlížeče.
  2. V aplikaci Internet Explorer selže nastavení intervalu nulového zpoždění (.., 0). To platí konkrétně pro setInterval, tzn. setTimeout (.., 0) funguje dobře.

Skutečná frekvence odezvy

Může být spouštěn mnohem méně často, v některých případech nemusí být zpoždění 4 ms, ale 30 ms nebo dokonce 1 000 ms.

Většina prohlížečů (na prvním místě desktop) nadále provádí setTimeout / setInterval, i když je karta neaktivní. Zároveň řada z nich (Chrome, FF, IE10) snižuje minimální frekvenci časovače až na 1x za sekundu. Ukazuje se, že časovač bude fungovat na kartě "pozadí", ale zřídka.

Při provozu na baterii v notebooku mohou prohlížeče také snížit frekvenci, aby spouštěly kód méně často a šetřily energii baterie. IE je tím zvláště známý. Snížení může být až několikanásobné v závislosti na nastavení. Pokud je zatížení procesoru příliš velké, JavaScript nemusí být schopen zpracovat časovače včas. Tím přeskočíte některé běhy setInterval.

Závěr: měli byste se řídit frekvencí 4ms, ale neměli byste s ní počítat.

Výstup intervalů do konzole Kód, který počítá intervaly mezi voláními, vypadá asi takto:

var timeMark = new Date; setTimeout ( funkce go ()(var diff = new Date - timeMark; // vytiskne místo stránky další zpoždění do konzole konzola .log (rozdíl); // vzpomeňte si na čas na samém konci, // pro přesné měření zpoždění mezi hovory timeMark = new Date; setTimeout (go, 100); ), 100 );

Trik setTimeout (func, 0).

Tento trik stojí za to vstoupit do análů hacků JavaScriptu.

Funkce je zabalena do setTimeout (func, 0), pokud ji chcete spustit po skončení aktuálního skriptu.

Jde o to, že setTimeout nikdy neprovede funkci hned. Plánuje pouze její realizaci. Ale interpret JavaScriptu začne provádět plánované funkce až po provedení aktuálního skriptu.

Standardně setTimeout stejně nemůže vykonat funkci se zpožděním 0. Jak jsme si řekli dříve, obvykle bude zpoždění 4 ms. Ale hlavní věc je, že provedení v každém případě bude po provedení aktuálního kódu.

Například:

var výsledek; funkce showResult ()(upozornění (výsledek);) setTimeout (showResult, 0); výsledek = 2 * 2; // vytiskne 4

Celkový

Metody setInterval (func, delay) a setTimeout (func, delay) umožňují spouštění func pravidelně / jednou po prodlevě v milisekundách.

Obě metody vrátí ID časovače. Používá se k zastavení provádění voláním clearInterval / clearTimeout.

| | nastavitInterval | setTimeout | || ----------- | ---------- | | Načasování | Tam je volání přísně na časovač. Pokud je tlumočník zaneprázdněn, zařadí se do fronty jeden hovor. Doba provádění funkce se nebere v úvahu, takže časový interval od konce jednoho běhu do začátku druhého může být různý. | Místo setInterval se používá rekurzivní volání setTimeout, kde je potřeba pevná pauza mezi spuštěními. | | Zpoždění | Minimální zpoždění: 4 ms. | Minimální zpoždění: 4 ms. | | Funkce prohlížeče | Delay 0 nefunguje v IE | V Opeře je nulová latence ekvivalentní 4 ms, ostatní zpoždění jsou zpracována přesně, včetně nestandardních 1 ms, 2 ms a 3 ms. |

Při programování ve skriptovacích jazycích je periodicky nutné vytvořit pauzu - na chvíli pozastavit provádění programu a poté pokračovat v práci. Například ve skriptech VBS a PHP jsou možné následující metody:

VBS: wscript.sleep 1500 (zastavení na 1,5 sekundy)

PHP: spánek (10); (zastavte se na 10 sekund)

Během těchto přestávek běžící systém (PHP nebo VBS) nicnedělání... Vývojář, který se snaží něco takového intuitivně použít v Javascriptu, bude nemile překvapen. Typická chyba při pokusu o vytvoření pauzy v Javascriptu vypadá takto:

Funkce badtest () (pro (var i = 1; i< 10; i++) { window.setTimeout("document.getElementById("test1").value += " + i, 900) } }

Myslíte si, že když při průchodu smyčkou dojde na kreslení další číslice, vaší setTimeoutčestně zastaví práci Javascriptu, počká 0,9 sekundy, přidá požadované číslo na konec vstupního pole a poté pokračuje v práci. Ale ve skutečnosti to není: nastavitInterval a setTimeout v Javascriptu je zpožděna pouze akce (nebo funkce) uvedená v závorkách. V našem příkladu se stane následující:

  1. i = 1;
  2. odložit přidání čísla "1" do vstupního pole o 0,9 sekundy;
  3. ihned po nastavení tohoto problému cyklus pokračuje: i = 2;
  4. odložit přidání čísla „2“ do vstupního pole o 0,9 sekundy;

Ihned znamená například 1 ms (to je nesrovnatelně málo ve srovnání s 900 ms): cyklus vykoná svou práci téměř okamžitě a vytvoří několik nevyřízených úkolů ze stejného okamžiku. To znamená, že všechny čekající úkoly "kreslení" budou dokončeny téměř ve stejnou dobu, bez pauz mezi přidáváním nových čísel. Cyklus začíná; vše zamrzne na 0,9 s; a shirrr - všechna čísla jsou střílena v řadě za sebou.

A jak je v takovém případě správně aplikovat setTimeout? Je to komplikované. Je třeba zavolat funkci rekurzivně(zevnitř funkce, stejná funkce), a aby tento proces nebyl nekonečný, nastavte podmínku zastavení (například hodnotu vytištěného čísla):

Funkční welltest () (pokud (i< 9) { document.getElementById("test2").value += ++i window.setTimeout("welltest()", 400) } }

A další proměnná i bude muset být inicializován mimo funkci - například takto:

Nyní vše funguje jak má (zkrátili jsme dobu zpoždění z 0,9 s na 0,4 s). Ale pro takové úkoly je logičtější použít ne setTimeout A nastavitInterval(ačkoli by to vyžadovalo dvě funkce):

Function besttest () (window.i = 0 window.timer1 = window.setInterval ("draw ()", 400)) function draw () (document.getElementById ("test3")). Hodnota + = ++ i if (i > = 9) clearInterval (window.timer1))

Funkce metody Javascirpt nastavitInterval to, že to neprojde „samo“, je třeba to zastavit speciální metodou clearInterval... A aby bylo jasné, co zastavit, je úkolu odložené akce přiřazen speciální identifikátor – časovač: window.timer1 = window.setInterval (...).

Úkolům vytvořeným touto metodou lze také přiřadit identifikátory setTimeout... Všechna ID časovače se musí navzájem lišit (unikátní v aktuálním okně prohlížeče). Pak můžete v okně vytvořit několik různých úloh, které používají odložené akce, a tyto úlohy se budou provádět paralelně (něco jako současně, pokud má počítač dostatek zdrojů), což je v PHP nebo VBS v podstatě nemožné.

Zde je příklad stránky s více časovači Javascript spuštěnými současně: setinterval.htm (funkce JavaScriptu v souboru setinterval.js). Činnost všech časovačů stránky (kromě nabídky) lze zastavit stisknutím klávesy Esc. Všechny ukázkové časovače spoléhají na „přirozené“ (nikoli abstraktní já ++) odpočítávání - čas nebo vzdálenost. Všechny "hodiny" jsou speciálně desynchronizované (pro přehlednost). Časovače založené na vzdálenosti se používají v „indikátoru“ a v rozbalovací (rozbalovací) nabídce.

Rozbalovací nabídka

Naše výsuvná nabídka je ve skutečnosti výsuvná (zpod "záhlaví"): mezi prvky jsou mezery, aby bylo vidět, jak se vytahuje. Nečekaně se ukázalo, že stejně plynulý výstup u různě dlouhých seznamů neumíme – pravděpodobně kvůli nízkému výkonu počítače (AMD Athlon 999 MHz).

Je zcela zřejmé, že pro krásu a harmonii je nutné, aby se seznamy různých položek menu objevovaly současně. To znamená, že delší seznamy by měly vypadávat rychleji, kratší seznamy - nižší rychlostí. Zdá se, že to lze implementovat takto:

  1. Celkový čas „odjezdu“ nastavíme např. na 200 ms.
  2. Pokud má rozevírací seznam výšku 20 px, je zřejmé, že jej můžeme posouvat o jeden pixel dolů v čase 10 ms – a za 200 ms se pak celý seznam vyleze ven.
  3. Pokud je rozevírací seznam vysoký 40 pixelů, abychom se vešli současně, musíme jej posouvat o jeden pixel dolů za 5 ms.

Podle této logiky, pokud je rozevírací seznam vysoký 200 px, musíme jej posouvat o jeden pixel dolů za 1 ms. Tato rychlost ale na našem počítači nefunguje – prohlížeč prostě nestihne nakreslit novou pozici seznamu za jednu milisekundu. Ano. Javascript má čas počítat (co se má počítat?), ale prohlížeč (Firefox) nemá čas zobrazovat. Typická situace pro web.

Dobu opuštění menu je tedy možné víceméně vyrovnat pouze pomocí berliček a zatím není jasné, jak to bude fungovat na rychlejším počítači. Ale musíme počítat s tím nejpomalejším, že? Algoritmus (bez zohlednění rychlosti počítače) vypadá takto:

  1. Nastavíme celkový čas pokladny seznamu: čas = 224 (ms).
  2. Nastavíme minimální čas pro jeden interval v cyklu: zpoždění = 3 (ms).
  3. Nastavte minimální krok pro přesun seznamu: offset = 1 (px).
  4. To vše měníme v závislosti na výšce seznamu: 1) zvyšujeme čas zpoždění (intervalu) nepřímo úměrně výšce a přímo úměrně celkovému času času (při výšce 224 je koeficient 1); 2) pokud je výška větší než 40 px, zvyšte minimální krok úměrně výšce. Konstanta „40“ se získá empiricky pro nejpomalejší počítač. Testy na počítači Pentium 4 CPU 2,53GHz odhalily úplně stejné číslo – 40. Jinak časovače šílí, seznamy nedrží krok.

Nyní se seznamy víceméně rozjíždějí. Na víceméně podobnou dobu. Na stránce setinterval.htm.

A tady je Bru-mustache:

Funkce slide_do (obj, maxtop, offset) (if (getTopLeft (obj) .top< maxtop) { obj.style.top = getTopLeft(obj).top + offset } else { if (obj && obj.timer1) { clearInterval(obj.timer1) obj.timer1 = null } } }

Samotná funkce, která vytahuje vnořené seznamy z nabídky, je, jak vidíte, velmi jednoduchá. Zbývá pouze spustit jej s něčím jako je tento řádek:

Ts.timer1 = setInterval (funkce () (slide_do (ts, maxtop, offset)), zpoždění)

Než začnete, stačí vypočítat všechny tyto maxtop a offset a také umístit seznam na pozici mintop. Co dělá "předběžná" funkce snímek () Velikost 40 řádků. A to vše dohromady – v souboru setinterval.js. Ano, a tahle kravina nebude fungovat bez přiložené šablony stylů.