Časovače v Javascripte (setInterval, setTimeout). O tom, ako fungujú časovače JavaScriptu Opakujte akcie v zadanom časovom intervale javascript

Domov / Operačné systémy

Časový limit JavaScriptu je natívna funkcia JavaScriptu, ktorá spúšťa časť kódu po určitom časovom oneskorení (v milisekundách). To môže byť užitočné, keď potrebujete zobraziť kontextové okno po tom, čo používateľ strávil nejaký čas na vašej stránke. Alebo chcete, aby sa efekt, keď umiestnite kurzor myši na prvok, spustil až po uplynutí určitého času? Týmto spôsobom sa môžete vyhnúť neúmyselnému spusteniu efektu, ak naň používateľ náhodne umiestnil kurzor myši.

Jednoduchý príklad setTimeout

Ak chcete demonštrovať, ako táto funkcia funguje, navrhujem pozrieť si nasledujúcu ukážku, v ktorej sa dve sekundy po kliknutí na tlačidlo zobrazí kontextové okno.

Zobraziť ukážku

Syntax

Dokumentácia MDN poskytuje nasledujúcu syntax pre setTimeout:

var timeoutID = window.setTimeout(func, ); var timeoutID = window.setTimeout(code, );

  • timeoutID – číselné ID, ktoré možno použiť v kombinácii s clearTimeout() na vypnutie časovača;
  • func – funkcia, ktorá sa má vykonať;
  • kód (v alternatívnej syntaxi) – riadok kódu, ktorý sa má vykonať;
  • oneskorenie – trvanie oneskorenia v milisekundách, po ktorom sa funkcia spustí. Predvolená hodnota je 0.
setTimeout vs window.setTimeout

Vyššie uvedená syntax používa window.setTimeout . prečo?

V skutočnosti sú setTimeout a window.setTimeout prakticky rovnaké funkcie. Jediný rozdiel je v tom, že v druhom výraze používame metódu setTimeout ako vlastnosť objektu globálneho okna.

Osobne si myslím, že to robí kód oveľa komplikovanejším. Ak sme definovali alternatívna metódaČasový limit JavaScriptu, ktorý by sa dal nájsť a vrátiť prioritne, by potom narazil na ešte väčšie problémy.

V tomto návode sa nechcem motať s objektom okna, ale vo všeobecnosti je len na vás, akú syntax použijete.

Príklady použitia

Toto môže byť názov funkcie:

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

Premenná, ktorá odkazuje na funkciu:

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

Alebo anonymná funkcia:

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

  • Takýto kód je zle pochopený, a preto bude ťažké ho modernizovať alebo ladiť;
  • Zahŕňa použitie metódy eval(), ktorá by mohla predstavovať potenciálnu zraniteľnosť;
  • Táto metóda je pomalšia ako ostatné, pretože vyžaduje spustenie prekladača JavaScriptu.

Upozorňujeme tiež, že na testovanie kódu používame metódu upozornenia na časový limit JavaScriptu.

Odovzdanie parametrov do setTimout

V prvej (a cross-browser) možnosti odovzdávame parametre funkcii spätného volania, vykonávanej pomocou setTimeout.

V nasledujúcom príklade extrahujeme náhodný pozdrav z poľa pozdravov a odovzdáme ho ako parameter funkcii greet(), ktorú vykoná setTimeout s oneskorením 1 sekundy:

function greet(pozdrav)( console.log(pozdrav); ) function getRandom(arr)( return arr; ) var pozdravy = ["Ahoj", "Bonjour", "Guten Tag"], randomGreeting = getRandom(zdravím); setTimeout(funkcia())( pozdrav(nahodny pozdrav); ), 1000);

Zobraziť ukážku

Alternatívna metóda

V syntaxi uvedenej na začiatku článku existuje ďalšia metóda, pomocou ktorej môžete odovzdať parametre funkcii spätného volania vykonanej časovým limitom JavaScriptu. Táto metóda znamená výstup všetkých parametrov po oneskorení.

Na základe predchádzajúceho príkladu dostaneme:

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

Táto metóda nebude fungovať v IE 9 a nižších verziách, kde sa odovzdané parametre považujú za nedefinované . Na vyriešenie tohto problému však existuje špeciálny polyfill na MDN.

Súvisiace problémy a „toto“

Kód spustený setTimeout beží oddelene od funkcie, ktorá ho volala. Z tohto dôvodu sa stretávame s určitými problémami, ktoré je možné vyriešiť použitím kľúčového slova this.

var osoba = ( meno: "Jim", predstavte: function())( console.log("Ahoj, ja som " + this.firstName); ) ); osoba.introduce(); // Výstupy: Ahoj, ja " m Jim setTimeout(person.introduce, 50); // Výstupy: Ahoj, ja som nedefinovaný

Dôvodom tohto výstupu je, že v prvom príklade to ukazuje na objekt osoba a v druhom príklade ukazuje na objekt globálneho okna, ktorý nemá vlastnosť firstName.

Ak sa chcete zbaviť tejto nezrovnalosti, môžete použiť niekoľko metód:

Vynútiť nastavenie

Dá sa to urobiť pomocou bind(), metódy, ktorá vytvorí novú funkciu, ktorá pri volaní používa špecifickú hodnotu ako hodnotu tohto kľúča. V našom prípade ide o objekt určenej osoby. To nám v konečnom dôsledku dáva:

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

Poznámka: Metóda väzby bola zavedená v ECMAScript 5, čo znamená, že bude fungovať iba v moderné prehliadače. V iných, keď ho použijete, dostanete chybu spustenia JavaScriptu „chyba časového limitu funkcie“.

Použite knižnicu

Mnohé knižnice obsahujú vstavané funkcie potrebné na vyriešenie tohto problému. Napríklad metóda jQuery.proxy(). Zoberie funkciu a vráti novú, ktorá bude vždy používať špecifický kontext. V našom prípade bude kontext:

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

Zobraziť ukážku

Vypnutie časovača

Návratová hodnota setTimeout je číselné ID, ktoré možno použiť na zakázanie časovača pomocou funkcie clearTimeout():

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

Pozrime sa na to v praxi. Ak v nasledujúcom príklade kliknete na tlačidlo „Spustiť odpočítavanie“, odpočítavanie sa spustí. Po jeho dokončení dostanú mačiatka svoje. Ak však kliknete na tlačidlo „Zastaviť odpočítavanie“, časovač časového limitu JavaScript sa zastaví a vynuluje.

Zobraziť príklad

Poďme si to zhrnúť

setTimeout je asynchrónna funkcia, čo znamená, že výsledné volanie tejto funkcie sa zaradí do frontu a vykoná sa až po dokončení všetkých ostatných akcií v zásobníku. Nemôže bežať súčasne s inými funkciami alebo samostatným vláknom.

Metóda setInterval() ponúkaná na rozhraniach Window a Worker opakovane volá funkciu alebo vykonáva úryvok kódu s pevným časovým oneskorením medzi každým volaním.

Vracia ID intervalu, ktoré jedinečne identifikuje interval, takže ho môžete neskôr odstrániť volaním clearInterval() . Táto metóda je definovaná mixínom WindowOrWorkerGlobalScope. Syntax = var intervalID rozsah .setInterval(, func, [meškanie, arg1, ...]); Syntax = var intervalID rozsah arg2, func kód ); Parametre func Funkcia, ktorá sa má vykonať pri každom oneskorení v milisekundách. Funkcii sa neodovzdávajú žiadne argumenty a neočakáva sa žiadna návratová hodnota. z rovnakých dôvodov, pre ktoré je používanie eval() bezpečnostným rizikom. .setInterval( oneskorenie Čas v milisekundách (tisícina sekundy), ktorý by mal časovač oddialiť medzi vykonaním špecifikovanej funkcie alebo kódu. Podrobnosti o povolenom rozsahu hodnôt oneskorenia nájdete nižšie.

arg1, ..., argN Voliteľné Dodatočné argumenty, ktoré sa prenesú do funkcie špecifikovanej pomocou akonáhle časovač vyprší. Poznámka: Odovzdanie ďalších argumentov do setInterval() v prvej syntaxi nefunguje

Internet Explorer

9 a skôr. Ak chcete povoliť túto funkciu v tomto prehliadači, musíte použiť polyfill (pozri časť).

Návratová hodnota

Vrátený intervalID je číselná, nenulová hodnota, ktorá identifikuje časovač vytvorený volaním funkcie setInterval() ; táto hodnota môže byť odovzdaná na zrušenie časového limitu.

Môže byť užitočné uvedomiť si, že setInterval() a setTimeout() zdieľajú rovnaký súbor ID a že clearInterval() a clearTimeout() možno technicky používať zameniteľne. Kvôli prehľadnosti by ste sa však mali snažiť ich vždy zhodovať, aby ste predišli zmätku pri údržbe kódu.

Poznámka: Argument oneskorenia sa skonvertuje na 32-bitové celé číslo so znamienkom. Toto efektívne obmedzuje oneskorenie na 2147483647 ms, pretože je špecifikované ako celé číslo so znamienkom v IDL.

Príklady Príklad 1: Základná syntax

Nasledujúci príklad demonštruje základnú syntax setInterval() ".

Var intervalID = window.setInterval(myCallback, 500, "Parameter 1", "Parameter 2"); function myCallback(a, b) ( // Váš kód tu // Parametre sú čisto voliteľné. console.log(a); console.log(b); )

Príklad 2: Striedanie dvoch farieb

Nasledujúci príklad volá funkciu flashtext() raz za sekundu, kým nestlačíte tlačidlo Stop.

setInterval/clearInterval príklad var nIntervId;

function changeColor() ( nIntervId = setInterval(flashText, 1000); ) function flashText() ( var oElem = document.getElementById("my_box"); oElem.style.color = oElem.style.color == "red" ? " blue" : "red"; // oElem.style.color == "red" ? "blue" : "red" je ternárny operátor. ) funkcia stopTextColor() ( clearInterval(nIntervId); )

Ahoj svet

JavaScript Typewriter - MDN Príklad funkcie Typewriter (sSelector, nRate) ( funkcia clean () ( clearInterval(nIntervId); bTyping = false; bStart = true; oCurrent = null; aSheets.length = nIdx = 0; ) rolovanie funkcie (oSheet, nPos , bEraseAndStop) ( if (!oSheet.hasOwnProperty("časti") || aMap.length< nPos) { return true; } var oRel, bExit = false; if (aMap.length === nPos) { aMap.push(0); } while (aMap < oSheet.parts.length) { oRel = oSheet.parts]; scroll(oRel, nPos + 1, bEraseAndStop) ? aMap++ : bExit = true; if (bEraseAndStop && (oRel.ref.nodeType - 1 | 1) === 3 && oRel.ref.nodeValue) { bExit = true; oCurrent = oRel.ref; sPart = oCurrent.nodeValue; oCurrent.nodeValue = ""; } oSheet.ref.appendChild(oRel.ref); if (bExit) { return false; } } aMap.length--; return true; } function typewrite () { if (sPart.length === 0 && scroll(aSheets, 0, true) && nIdx++ === aSheets.length - 1) { clean(); return; } oCurrent.nodeValue += sPart.charAt(0); sPart = sPart.slice(1); } function Sheet (oNode) { this.ref = oNode; if (!oNode.hasChildNodes()) { return; } this.parts = Array.prototype.slice.call(oNode.childNodes); for (var nChild = 0; nChild < this.parts.length; nChild++) { oNode.removeChild(this.parts); this.parts = new Sheet(this.parts); } } var nIntervId, oCurrent = null, bTyping = false, bStart = true, nIdx = 0, sPart = "", aSheets = , aMap = ; this.rate = nRate || 100; this.play = function () { if (bTyping) { return; } if (bStart) { var aItems = document.querySelectorAll(sSelector); if (aItems.length === 0) { return; } for (var nItem = 0; nItem < aItems.length; nItem++) { aSheets.push(new Sheet(aItems)); /* Uncomment the following line if you have previously hidden your elements via CSS: */ // aItems.style.visibility = "visible"; } bStart = false; } nIntervId = setInterval(typewrite, this.rate); bTyping = true; }; this.pause = function () { clearInterval(nIntervId); bTyping = false; }; this.terminate = function () { oCurrent.nodeValue += sPart; sPart = ""; for (nIdx; nIdx < aSheets.length; scroll(aSheets, 0, false)); clean(); }; } /* usage: */ var oTWExample1 = new Typewriter(/* elements: */ "#article, h1, #info, #copyleft", /* frame rate (optional): */ 15); /* default frame rate is 100: */ var oTWExample2 = new Typewriter("#controls"); /* you can also change the frame rate value modifying the "rate" property; for example: */ // oTWExample2.rate = 150; onload = function () { oTWExample1.play(); oTWExample2.play(); }; span.intLink, a, a:visited { cursor: pointer; color: #000000; text-decoration: underline; } #info { width: 180px; height: 150px; float: right; background-color: #eeeeff; padding: 4px; overflow: auto; font-size: 12px; margin: 4px; border-radius: 5px; /* visibility: hidden; */ }

CopyLeft 2012 od Mozilla Developer Network

[ Prehrať | Pauza | Ukončiť]

Vivamus blandit massa ut metus mattis in fringilla lectus imperdiet. Proin ac ante a felis ornare vehicula. Fusce pellentesque lacus vitae eros convallis ut mollis magna pellentesque. Pellentesque placerat enim at lacus ultricies vitae facilisis nisi fringilla. In tincidunt tincidunt tincidunt.

JavaScript písací stroj

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices dolor ac dolor imperdiet ullamcorper. Suspendisse quam libero, luctus auctor mollis sed, malesuada condimentum magna. Quisque in ante tellus, in placerat est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec a mi magna, quis mattis dolor. Etiam sit amet ligula quis urna auctor imperdiet nec faucibus ante. Mauris vel consectetur dolor. Nunc eget elit eget velit pulvinar fringilla consectetur aliquam purus. Curabitur convallis, justo posuere porta egestas, velit erat ornare tortor, non viverra justo diam eget arcu. Phasellus adipiscing fermentum nibh ac commodo. Nam turpis nunc, suscipit a hendrerit vitae, volutpat non ipsum.
Phasellus ac nisl lorem:

Duis lobortis sapien quis nisl luctus porttitor. In tempor semper libero, eu tincidunt dolor eleifend sit amet. Ut nec velit in dolor tincidunt rhoncus non non diam. Morbi auctor ornare orci, non euismod felis gravida in. Curabitur elementum nisi a eros rutrum nec blandit diam placerat. Aenean tincidunt risus ut nisi consectetur cursus. Ut vitae quam elita. Donec dignissim est in quam tempor consequat. Aliquam aliquam diam non felis convallis suscipit. Nulla facilisi. Donec lacus risus, dignissim et fringilla et, egestas vel eros. Duis malesuada accumsan dui, at fringilla mauris bibStartum quis. Cras adipiscing ultricies fermentum. Praesent bibStartum condimentum feugiat.

Nam faucibus, ligula eu fringilla pulvinar, lectus tellus iaculis nunc, vitae scelerisque metus leo non metus. Proin Mattis Lobortis Lobortis. Quisque accumsan faucibus erat, vel varius tortor ultricies ac. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec libero nunc. Nullam tortor nunc, elementum a consectetur et, ultrices eu orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque a nisl eu sem vehicula egestas.

Argumenty spätného volania

Ako už bolo uvedené, Internet Explorer verzie 9 a nižšie nepodporujú odovzdávanie argumentov funkcii spätného volania v setTimeout() ani setInterval() . Nasledujúci kód špecifický pre IE demonštruje metódu na prekonanie tohto obmedzenia. Ak chcete použiť, jednoducho pridajte nasledujúci kód do hornej časti skriptu.

/*\ |*| |*| Polyfill špecifický pre IE, ktorý umožňuje prechod ľubovoľných argumentov do |*| funkcie spätného volania časovačov javascriptu (štandardná syntax HTML5)..setInterval |*| https://site/User:fusionchess |*| |*| Syntax: |*| var timeoutID = window.setTimeout(func, delay[, arg1, arg2, ...]); |*| var timeoutID = window.setTimeout(kód, oneskorenie); |*| var intervalID = window.setInterval(func, delay[, arg1, arg2, ...]); |*| var intervalID = window.setInterval(kód, oneskorenie); |*| \*/ if (document.all && !window.setTimeout.isPolyfill) ( var __nativeST__ = window.setTimeout; window.setTimeout = funkcia (vCallback, nDelay /*, argumentToPass1, argumentToPass2 atď. */) ( var aArgs = Array .prototype.slice.call(arguments, 2) return __nativeST__(vCallback instanceof Function () ( vCallback.apply(null, aArgs); ) : vCallback, nDelay if (document.all && !window.setInterval.isPolyfill) ( var __nativeSI__ = window.setInterval; window.setInterval = funkcia (vCallback, nDelay /*, argumentToPass1, argumentToPass2 atď. */) ( var aArgs = Array.prototype. slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function () ( vCallback.apply(null, aArgs); ) : vCallback, nDelay );

Ďalšou možnosťou je použiť anonymnú funkciu na spätné volanie, aj keď toto riešenie je o niečo drahšie. Príklad:

Var intervalID = setInterval(function() ( myFunc("jeden", "dva", "tri"); ), 1000);

var intervalID = setInterval(funkcia(arg1) ().bind(nedefinovane, 10), 1000);

Neaktívne karty Vyžaduje Gecko 5.0 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2)

Počnúc verziou Gecko 5.0 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2) sa na neaktívnych kartách intervaly spúšťajú nie častejšie ako raz za sekundu.

"Tento" problém

Keď odovzdáte metódu setInterval() alebo akejkoľvek inej funkcii, vyvolá sa s nesprávnou hodnotou. Tento problém je podrobne vysvetlený v referencii JavaScript.

Vysvetlenie

MyArray = ["nula", "jedna", "dva"]; myArray.myMethod = function (sProperty) ( alert(arguments.length > 0 ? this : this); ); myArray.myMetoda(); // vypíše "nula,jedna,dva" myArray.myMethod(1); // vypíše "jeden" setTimeout(myArray.myMethod, 1000); // vypíše "" po 1 sekunde setTimeout(myArray.myMethod, 1500, "1"); // vypíše "undefined" po 1,5 sekunde // odovzdanie "this" objektu pomocou .call nebude fungovať // pretože to zmení hodnotu tohto v samotnom setTimeout // zatiaľ čo my chceme zmeniť hodnotu tohto vo vnútri myArray .myMethod // v skutočnosti to bude chyba, pretože kód setTimeout očakáva, že toto bude objekt okna: setTimeout.call(myArray, myArray.myMethod, 2000 // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Neplatná operácia na objekte WrappedNative prototype); setTimeout.call(myArray, mojePole.myMetoda, 2500, 2);

Ako vidíte, neexistujú žiadne spôsoby, ako odovzdať tento objekt funkcii spätného volania v starom jazyku JavaScript.

Možné riešenie

Možným spôsobom, ako vyriešiť „tento“ problém, je nahradiť dve natívne globálne funkcie setTimeout() alebo setInterval() dvoma nepôvodný tie, ktoré umožňujú ich vyvolanie prostredníctvom metódy Function.prototype.call. Nasledujúci príklad ukazuje možnú náhradu:

// Povolenie prechodu „tohto“ objektu cez časovače JavaScript var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval; window.setTimeout = funkcia (vCallback, nDelay /*, argumentToPass1, argumentToPass2 atď. */) ( var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function ? function () ( vCallback.apply(oThis, aArgs); ) : vCallback, nDelay ); window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2 atď. */) ( var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function ? function () ( vCallback.apply(oThis, aArgs); ) : vCallback, nDelay );

Tieto dve náhrady tiež umožňujú štandardný HTML5 prechod ľubovoľných argumentov do funkcií spätného volania časovačov v IE. Takže môžu byť použité ako neštandardne vyhovujúce polyfilly tiež. Pozrite si a v súlade s normou polyfill

Test novej funkcie:

MyArray = ["nula", "jedna", "dva"]; myArray.myMethod = function (sProperty) ( alert(arguments.length > 0 ? this : this); ); setTimeout(upozornenie, 1500, "Ahoj svet!"); // štandardné použitie setTimeout a setInterval je zachované, ale... setTimeout.call(myArray, myArray.myMethod, 2000); // po 2 sekundách vypíše "nula,jedna,dva" setTimeout.call(myArray, myArray.myMethod, 2500, 2); // vypíše "dve" po 2,5 sekundách

Pre komplexnejšiu, ale stále modulárnu verziu ( Démon) pozri Správa démonov JavaScript . Táto zložitejšia verzia nie je nič iné ako veľká a škálovateľná zbierka metód pre Démon konštruktér. Avšak, Démon Konštruktor sám o sebe nie je nič iné ako klon MiniDaemon s pridanou podporou init a na začiatku funkcie deklarované počas vytvárania inštancie démon. Takže MiniDaemon framework zostáva odporúčaným spôsobom pre jednoduché animácie, pretože Démon bez jeho zbierky metód je v podstate jeho klonom.

minidaemon.js /*\ |*| |*| :: MiniDaemon:: |*| |*| Revízia č. 2 – 26. septembra 2014.setInterval |*| https://site/User:fusionchess |*| https://github.com/madmurphy/minidaemon.js |*| |*| Tento rámec je vydaný pod licenciou GNU Lesser General Public License, verzia 3 alebo novšia. |*| http://www.gnu.org/licenses/lgpl-3.0.html |*| \*/ function MiniDaemon (oOwner, fTask, nRate, nLen) ( if (!(this && this instanceof MiniDaemon)) ( return; ) if (arguments.length< 2) { throw new TypeError("MiniDaemon - not enough arguments"); } if (oOwner) { this.owner = oOwner; } this.task = fTask; if (isFinite(nRate) && nRate >0) ( this.rate = Math.floor(nRate); ) if (nLen > 0) ( this.length = Math.floor(nLen); ) ) MiniDaemon.prototype.owner = null; MiniDaemon.prototype.task = null; MiniDaemon.prototype.rate = 100; MiniDaemon.prototype.length = Infinity;< 1: this.INDEX + 1 >táto.dĺžka; ); MiniDaemon.prototype.synchronize = function () ( if (this.PAUSED) ( return; ) clearInterval(this.SESSION); this.SESSION = setInterval(MiniDaemon.forceCall, this.rate, this); ); MiniDaemon.prototype.pause = function () ( clearInterval(this.SESSION); this.PAUSED = true; ); MiniDaemon.prototype.start = funkcia (bReverse) ( var bBackw = Boolean(bReverse); if (this.BACKW === bBackw && (this.isAtEnd() || !this.PAUSED)) ( return; ) this.BACKW = bBackw toto.PAUSED = false.synchronize();

MiniDaemon odovzdá argumenty funkcii spätného volania. Ak na ňom chcete pracovať s prehliadačmi, ktoré túto funkciu natívne nepodporujú, použite jednu z vyššie navrhnutých metód.

Syntax

var myDaemon = nový MiniDaemon( tentoObjekt, spätné volanie[ , sadzba [, dĺžka]]);

Popis Poznámky k použitiu

Funkcia setInterval() sa bežne používa na nastavenie oneskorenia pre funkcie, ktoré sa vykonávajú znova a znova, ako sú napríklad animácie. Interval môžete zrušiť pomocou WindowOrWorkerGlobalScope.clearInterval() .

Ak si želáte zavolať vašu funkciu raz po určenom oneskorení použite .

Obmedzenia oneskorenia

Je možné, že intervaly budú vnorené; to znamená, že spätné volanie pre setInterval() môže zase zavolať setInterval() na spustenie ďalšieho intervalu, aj keď prvý stále prebieha. Na zmiernenie potenciálneho dopadu Keď sú intervaly vnorené nad päť úrovní, prehliadač automaticky vynúti minimálnu hodnotu intervalu 4 ms. Pokusy zadať hodnotu menšiu ako 4 ms v hlboko vnorených volaniach funkcie setInterval() budú pripnuté na 4 ms.

Prehliadače môžu za určitých okolností vynútiť ešte prísnejšie minimálne hodnoty intervalu, aj keď by to nemalo byť bežné. Upozorňujeme tiež, že skutočný čas, ktorý uplynie medzi volaniami na spätné volanie, môže byť dlhší ako dané oneskorenie; príklady nájdete v časti Dôvody oneskorení dlhších, ako je uvedené v WindowOrWorkerGlobalScope.setTimeout().

Uistite sa, že trvanie vykonávania je kratšie ako intervalová frekvencia

Ak existuje možnosť, že spustenie vašej logiky môže trvať dlhšie, než je časový interval, odporúča sa rekurzívne zavolať pomenovanú funkciu pomocou setTimeout() . Napríklad, ak použijete setInterval() na dotazovanie vzdialeného servera každých 5 sekúnd, latencia siete, nereagujúci server a množstvo ďalších problémov môžu zabrániť dokončeniu požiadavky v určenom čase. Preto sa môžete ocitnúť vo fronte s požiadavkami XHR, ktoré sa nemusia nevyhnutne vrátiť v poriadku.

Je mimoriadne dôležité pochopiť, ako fungujú časovače JavaScriptu. Ich správanie často nezodpovedá nášmu intuitívnemu chápaniu multithreadingu a je to spôsobené tým, že v skutočnosti sú vykonávané v jednom vlákne. Pozrime sa na štyri funkcie, pomocou ktorých môžeme spravovať časovače:

  • var id = setTimeout(fn, oneskorenie); - Vytvorí jednoduchý časovač, ktorý zavolá danú funkciu po danom oneskorení. Funkcia vracia jedinečné ID, pomocou ktorého je možné časovač pozastaviť.
  • var id = setInterval(fn, oneskorenie); - Podobné ako setTimeout, ale nepretržite volá funkciu v určenom intervale (až do zastavenia).
  • clearInterval(id);, clearTimeout(id); - Prijme ID časovača (vrátené jednou z funkcií opísaných vyššie) a zastaví vykonávanie spätného volania"a.
Hlavnou myšlienkou, ktorú treba zvážiť, je, že nie je zaručená presnosť doby oneskorenia časovača. Na začiatok prehliadač vykonáva všetky asynchrónne udalosti JavaScriptu v jednom vlákne (ako sú kliknutia myšou alebo časovače) a iba v čase, keď je na rade táto udalosť. Najlepšie to ukazuje nasledujúci diagram:

Tento obrázok obsahuje pomerne veľa informácií, ale ich pochopenie vám poskytne hlbšie pochopenie toho, ako funguje asynchrónnosť JavaScriptu. Tento graf predstavuje čas vertikálne v milisekundách, modré bloky zobrazujú bloky kódu JavaScript, ktoré boli spustené. Napríklad prvý blok sa vykoná v priemere za 18 ms, kliknutie myšou blokuje spustenie na približne 11 ms atď.

JavaScript môže vykonávať iba jeden kus kódu (kvôli jednovláknovej povahe vykonávania), z ktorých každý blokuje vykonávanie iných asynchrónnych udalostí. To znamená, že keď sa vyskytne asynchrónna udalosť (napríklad kliknutie myšou, volanie časovača alebo dokončenie požiadavky XMLHttp), pridá sa do frontu a vykoná sa neskôr (implementácia sa samozrejme líši podľa prehliadača, ale dohodnime sa nazývame to „front“).

Na začiatok si predstavme, že v bloku JavaScriptu začínajú dva časovače: setTimeout s oneskorením 10 ms a setInterval s rovnakým oneskorením. Podľa toho, kedy sa časovač spustí, sa spustí v momente, keď ešte nemáme dokončený prvý blok kódu. Všimnite si však, že sa nespustí okamžite (to nie je možné kvôli jednoduchému závitu). Namiesto toho je odložená funkcia zaradená do frontu a vykonaná v najbližšom dostupnom momente.

Počas vykonávania prvého bloku JavaScript tiež dôjde ku kliknutiu myšou. Obslužný program pre túto asynchrónnu udalosť (a je asynchrónny, pretože ju nemôžeme predpovedať) nie je možné v tejto chvíli vykonať priamo, takže tiež skončí vo fronte, ako časovač.

Po vykonaní prvého bloku kódu JavaScript prehliadač položí otázku: „Čo čaká na vykonanie?“ IN v tomto prípade Ovládač kliknutia myšou a časovač sú v stave čakania. Prehliadač vyberie jeden z nich (obslužný program kliknutia) a spustí ho. Časovač bude čakať na ďalší dostupný čas vo fronte vykonávania.

Všimnite si, že kým sa vykonáva obsluha kliknutia myšou, spustí sa prvé spätné volanie intervalu. Rovnako ako spätné volanie časovača bude zaradené do frontu. Pamätajte však, že keď sa interval znova spustí (keď beží spätné volanie časovača), bude odstránený z frontu. Ak by boli všetky intervalové spätné volania zaradené do frontu počas vykonávania veľkého množstva kódu, viedlo by to k množstvu funkcií čakajúcich na zavolanie, pričom medzi nimi by neboli žiadne oneskorenia pri dokončení vykonávania. Namiesto toho majú prehliadače tendenciu čakať, kým nebudú žiadne ďalšie funkcie pred pridaním ďalšieho do poradia.

Môžeme teda pozorovať prípad, keď sa tretie spustenie intervalového spätného volania zhoduje s okamihom, keď je už vykonané. To ilustruje dôležitý bod: intervalom nezáleží na tom, čo práve beží, budú pridané do frontu bez ohľadu na dobu oneskorenia medzi vykonaniami.

Nakoniec, po dokončení druhého intervalového spätného volania, uvidíme, že už nezostáva nič, čo by mal JavaScript spustiť. To znamená, že prehliadač opäť čaká na nové asynchrónne udalosti. Stane sa tak po 50 ms, kedy bude opäť fungovať intervalové spätné volanie. V tomto momente to nebude nič blokovať, takže to bude fungovať okamžite.

Pozrime sa na príklad, ktorý pekne ilustruje rozdiel medzi setTimeout a setInterval.
setTimeout(function())( /* Nejaký dlhý blok kódu... */ setTimeout(arguments.callee, 10); ), 10);
Tieto dve možnosti sú na prvý pohľad rovnocenné, no v skutočnosti nie sú. Kód používajúci setTimeout bude mať vždy oneskorenie najmenej 10 ms po predchádzajúcom hovore (môže to byť viac, ale nikdy nie menej), zatiaľ čo kód používajúci setInterval bude mať tendenciu volať každých 10 ms, bez ohľadu na to, kedy došlo k predchádzajúcemu hovoru.

Zhrňme všetko, čo bolo povedané vyššie:
- JavaScript engine používa jednovláknové prostredie, ktoré transformuje asynchrónne udalosti na front čakajúci na spustenie,
- Funkcie setTimeout a setInterval sa v asynchrónnom kóde vykonávajú zásadne odlišne,
- Ak sa časovač nedá spustiť v momentálne, bude odložené do nasledujúceho bodu vykonania (ktorý bude dlhší ako požadované oneskorenie),
- Intervaly (setInterval) môžu byť vykonávané jeden po druhom bez oneskorenia, ak ich vykonanie trvá dlhšie ako stanovené oneskorenie.

Toto všetko je extrémne dôležité informácie pre rozvoj. Vedieť, ako funguje JavaScript engine, najmä s množstvom asynchrónnych udalostí (čo sa často stáva), položí skvelý základ pre vytváranie pokročilých aplikácií.

Pri programovaní v skriptovacích jazykoch je pravidelne potrebné vytvoriť pauzu - na chvíľu pozastaviť vykonávanie programu a potom pokračovať v práci. Napríklad v skriptoch VBS a PHP sú možné nasledujúce metódy:

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

PHP: spánok(10); (zastavte na 10 sekúnd)

Počas takýchto prestávok bude runtime systém (PHP alebo VBS) nerobí nič. Vývojár snažiaci sa intuitívne použiť niečo podobné v Javascripte bude nepríjemne prekvapený. Typická chyba pri pokuse o vytvorenie pauzy v Javascripte vyzerá takto:

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

Myslíte si, že keď počas cyklu príde rad na kreslenie ďalšieho čísla, váš setTimeout úprimne zastaví Javascript v práci, počká 0,9 sekundy, pridá požadované číslo na koniec vstupného poľa a potom pokračuje v práci. Ale v skutočnosti to tak nie je: setInterval a setTimeout v Javascripte iba oneskorujú vykonanie akcie (alebo funkcie) uvedenej v zátvorkách. V našom príklade sa stane nasledovné:

  • i = 1;
  • oneskorenie pridania čísla "1" do vstupného poľa o 0,9 sekundy;
  • Ihneď po nastavení tohto problému cyklus pokračuje: i=2;
  • oneskorenie pridania čísla "2" do vstupného poľa o 0,9 sekundy;
  • Okamžite znamená napríklad 1 ms (teda neúmerne málo v porovnaní s 900 ms): slučka vykoná svoju prácu takmer okamžite a vytvorí niekoľko odložených úloh z rovnakého časového bodu. To znamená, že všetky čakajúce úlohy „kreslenia“ budú dokončené takmer v rovnakom čase, bez prestávok medzi pridávaním nových čísel. Cyklus sa spustí; všetko zamrzne na 0,9 s; a shirr - všetky čísla sa strieľajú v rade za sebou.

    Ako v takomto prípade správne aplikovať setTimeout? Je to komplikované. Budete musieť zavolať funkciu rekurzívne(v rámci funkcie rovnaká funkcia), a aby tento proces nebol nekonečný, nastavte podmienku zastavenia (napríklad veľkosť čísla, ktoré sa má vytlačiť):

    Funkcia welltest() (ak (i< 9) { document.getElementById("test2").value += ++i window.setTimeout("welltest()", 400) } }

    A premenná i bude musieť byť inicializovaná mimo funkcie - napríklad takto:

    Teraz všetko funguje ako má (čas oneskorenia sme skrátili z 0,9 s na 0,4 s). Ale pre takéto úlohy je logickejšie použiť setInterval namiesto setTimeout (aj keď to bude vyžadovať dve funkcie):

    Funkcia besttest() ( window.i = 0 window.timer1 = window.setInterval("draw()", 400) ) funkcia draw() ( document.getElementById("test3").value += ++i if (i >= 9) clearInterval(window.timer1) )

    Zvláštnosťou metódy Javascirpt setInterval je, že neprechádza „sama od seba“ a musí byť zastavená špeciálnou metódou clearInterval. A aby bolo jasné, čo presne zastaviť, je úlohe pre odloženú akciu priradený špeciálny identifikátor - časovač: window.timer1 = window.setInterval(...) .

    Úlohám vytvoreným metódou setTimeout možno priradiť aj identifikátory. Všetky identifikátory časovačov musia byť navzájom odlišné (jedinečné v aktuálnom okne prehliadača). Potom môžete v okne vytvoriť niekoľko rôznych úloh, ktoré používajú odložené akcie, a tieto úlohy sa budú vykonávať paralelne (tak trochu súčasne, ak má počítač dostatok zdrojov), čo je v PHP alebo VBS v podstate nemožné.

    Tu je príklad stránky s niekoľkými súčasne spustenými časovačmi Javascript: setinterval.htm (funkcie JavaScriptu v súbore setinterval.js). Všetky časovače stránky (okrem ponuky) je možné zastaviť pomocou klávesu Esc. Všetky príklady časovačov sú založené na „prirodzenom“ (a nie abstraktnom i++) odpočítavaní – času alebo vzdialenosti. Všetky „hodiny“ sú špeciálne desynchronizované (pre prehľadnosť). Časovače závislé od vzdialenosti sa používajú v „indikátore“ a v rozbaľovacej („rozbaľovacej“) ponuke.

    Rozbaľovacia ponuka

    Naša posuvná ponuka je v skutočnosti posuvná (spod „hlavičky“): medzi prvkami sú špeciálne ponechané medzery, aby ste videli, ako sa vysúva. Nečakane sa ukázalo, že pre zoznamy rôznych dĺžok nedokážeme urobiť výstup rovnako hladký – pravdepodobne kvôli nízkemu výkonu počítača (AMD Athlon 999 MHz).

    Je celkom zrejmé, že pre krásu a harmóniu je potrebné, aby sa zoznamy rôznych položiek menu zobrazovali súčasne. To znamená, že dlhšie zoznamy by mali vypadnúť s ďalšími vysoká rýchlosť, kratšie - pri nižšej rýchlosti. Zdalo by sa, že by sa to dalo implementovať takto:

  • Celkový čas „odchodu“ nastavíme napríklad na 200 ms.
  • Ak má rozbaľovací zoznam výšku 20 px, je zrejmé, že ho môžeme posunúť o jeden pixel nadol za 10 ms interval – a potom o 200 ms vyjde celý zoznam.
  • Ak je rozbaľovacia ponuka vysoká 40 pixelov, aby sme sa zmestili za rovnaký čas, musíme ju každých 5 ms posunúť o jeden pixel nadol.
  • Podľa tejto logiky, ak je rozbaľovací zoznam vysoký 200 pixelov, mali by sme ho posunúť nadol o jeden pixel každú 1 ms. Takáto rýchlosť však na našom počítači nefunguje - prehliadač jednoducho nemá čas nakresliť novú pozíciu zoznamu za jednu milisekúndu. áno. Javascript zvláda počítať (čo sa tam má počítať?), ale prehliadač (Firefox) nestihne zobraziť. Typická situácia pre web.

    Preto je možné viac-menej vyrovnať čas odchodu z menu iba pomocou barlí a stále nie je jasné, ako to bude fungovať dlhšie rýchly počítač. Ale mali by sme rátať s tým najpomalším, nie? Algoritmus (bez zohľadnenia rýchlosti počítača) vyzerá takto:

  • Nastavte celkový čas pre kontrolu zoznamu: čas = 224 (ms).
  • Nastavíme minimálny čas pre jeden interval v cykle: oneskorenie = 3 (ms).
  • Nastavte minimálny krok pre presun zoznamu: offset = 1 (px).
  • Toto všetko meníme v závislosti od výšky zoznamu: 1) zvyšujeme čas oneskorenia (intervalu) v nepriamom pomere k výške a priamo úmerne k celkovému času času (pri výške 224 je koeficient 1); 2) ak je výška väčšia ako 40 px, zväčšite minimálny krok úmerne k výške. Konštanta "40" bola získaná experimentálne pre najpomalší počítač. Testy na počítači s procesorom Pentium 4 2,53 GHz odhalili presne to isté číslo – 40. V opačnom prípade časovače idú mimo poradia, zoznamy idú mimo krok.
  • Teraz zoznamy viac-menej vychádzajú. Na viac-menej podobný čas. Na stránke setinterval.htm.

    A tu prichádza Bruce:

    Funkcia 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á funkcia, ktorá vytláča vnorené zoznamy z ponuky, je, ako vidíme, veľmi jednoduchá. Všetko, čo zostáva, je spustiť ho s niečím takýmto riadkom:

    Ts.timer1 = setInterval(function())(slide_do(ts, maxtop, offset)), delay)

    No, pred začatím, len vypočítajte všetky tieto maxtop a offset, a tiež umiestnite zoznam na pozíciu mintop. Toto robí „predbežná“ funkcia slide() so 40 riadkami. A to všetko spolu – v súbore setinterval.js. Áno, a toto svinstvo nebude fungovať bez priloženého súboru štýlov

    • Od:
    • Registrovaný: 2014.07.08
    • Príspevkov: 3 896
    • Páči sa: 497
    Téma: SetTimeOut a SetInterval, čo je lepšie použiť v JavaScripte?

    Funkcia setInterval je navrhnutá na spustenie kódu viackrát v pravidelných intervaloch. Má však množstvo nevýhod, hlavne odlišné správanie v rôzne prehliadače.

    Prvým rozdielom je rozdiel v čase, v ktorom je nastavený časovač pre ďalšie spustenie. Vytvorme si malý test: budeme merať čas, ktorý uplynul od začiatku predchádzajúceho behu a od jeho konca.

    var d1 = nový dátum(), d2 = nový dátum(); setInterval(function() ( var d = new Date(); document.body.innerHTML += (d - d1) + " " + (d - d2) + "
    "; // Umiestnite značku na začiatok funkcie d1 = new Date(); while (new Date() - d1< 200); // ничего не делаем 200 миллисекунд // И в конце функции d2 = new Date(); }, 1000);

    Výstup bude informatívny od druhého riadku.

    V prehliadačoch Firefox, Opera, Safari a Chrome bude situácia podobná: prvé číslo bude približne rovné 1 000, druhé - o 200 menej. Rozdiel bude len v rozložení hodnôt. Najmenší rozdiel je v Chrome a Opera.

    2 Odpoveď od PunBB (upravené PunBB 2017.06.08 16:45)
    • Od: Moskva, Sovkhoznay 3, apt. 98
    • Registrovaný: 2014.07.08
    • Príspevkov: 3 896
    • Páči sa: 497

    Ďalším rozdielom, ktorý je menej viditeľný a ťažšie sa reprodukuje, no niekedy môže spôsobiť veľa problémov, je odolnosť voči zmenám systémového času. Ak spustíte nasledujúci test

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

    A po spustení nastavte systémový čas o minútu späť a potom na Prehliadače Firefox a Safari, zmena čísla sa pozastaví a po minúte sa znova spustí. Manuálny preklad systémového času je, samozrejme, mimoriadne zriedkavá situácia, ale mnohé systémy sú nakonfigurované tak, aby automaticky synchronizovali čas so servermi na internete, takže v niektorých situáciách nemožno tento faktor ignorovať.

    Ďalšou malou nevýhodou funkcie setInterval je, že aby ste mohli zastaviť jej činnosť, musíte si niekde zapamätať jej identifikátor, čo nie je vždy vhodné.

    3 Odpoveď od PunBB
    • Od: Moskva, Sovkhoznay 3, apt. 98
    • Registrovaný: 2014.07.08
    • Príspevkov: 3 896
    • Páči sa: 497
    Re: SetTimeOut a SetInterval, čo je lepšie použiť v JavaScripte?

    Aby ste sa zbavili uvedených nevýhod setInterval, môžete použiť viacero setTimeout.

    Dôležitou alternatívou k setInterval je rekurzívny setTimeout:

    /** namiesto: var timerId = setInterval(function() ( alert("tick"); ), 2000); */ var timerId = setTimeout(funkcia tick() ( alert("tick"); timerId = setTimeout(tick, 2000); ), 2000);

    Vo vyššie uvedenom kóde je ďalšie spustenie naplánované hneď po dokončení predchádzajúceho.

    Rekurzívny setTimeout je flexibilnejšia metóda časovania ako setInterval, pretože čas do ďalšieho spustenia možno naplánovať odlišne v závislosti od výsledkov aktuálneho spustenia.

    Napríklad máme službu, ktorá každých 5 sekúnd žiada server o nové údaje. Ak je server preťažený, môžete zvýšiť interval dotazovania na 10, 20, 60 sekúnd... A potom ho vrátiť späť, keď sa všetko vráti do normálu.

    Ak pravidelne spúšťame úlohy náročné na CPU, potom vieme odhadnúť čas strávený ich vykonávaním a ďalšie spustenie naplánovať skôr alebo neskôr.

    4 Odpoveď od PunBB
    • Od: Moskva, Sovkhoznay 3, apt. 98
    • Registrovaný: 2014.07.08
    • Príspevkov: 3 896
    • Páči sa: 497
    Re: SetTimeOut a SetInterval, čo je lepšie použiť v JavaScripte?

    Rekurzívny setTimeout zaručuje pauzu medzi hovormi, setInterval nie.

    Porovnajme tieto dva kódy. Prvý používa setInterval:

    var i = 1; setInterval(funkcia() ( func(i); ), 100);

    Druhý používa rekurzívny setTimeout:

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

    S setInterval sa interný časovač spustí presne každých 100 ms a zavolá funkciu func(i):

    Skutočná pauza medzi volaniami func s setInterval je menšia, ako je uvedené v kóde!

    Je to prirodzené, pretože prevádzkový čas funkcie sa nijako nezohľadňuje, časť intervalu „zožerie“.

    Je tiež možné, že funkcia func sa ukázala byť zložitejšia, než sme očakávali, a jej vykonanie trvalo dlhšie ako 100 ms.

    V tomto prípade tlmočník počká na dokončenie funkcie, potom skontroluje časovač a ak čas na volanie setInterval už nastal (alebo uplynul), ďalšie volanie prebehne okamžite.

    Ak funkcia beží dlhšie ako pauza setInterval, hovory prebehnú bez akéhokoľvek prerušenia.

    5 Odpoveď od sempai
    • Od: Jeruzalem
    • Registrovaný: 2015.06.02
    • Príspevkov: 958
    • Páči sa: 274
    Re: SetTimeOut a SetInterval, čo je lepšie použiť v JavaScripte?

    Všetko závisí od aktuálnej úlohy. Na začiatku sa SetTimeOut používa na jedno spustenie časovača a SetInterval sa používa na spustenie slučky. Obe funkcie však možno použiť na cyklické spúšťanie skriptov, ak ich napríklad spúšťate rekurzívne v Funkcie SetTimeOut, potom bude fungovať takmer rovnako ako SetInterval.

    Nevýhodou SetIntervalu je momentálne to, že neberie do úvahy čas vykonávania samotného skriptu (funkcie) a ak ho napríklad použijete na ťažké dotazy, tak sa čas intervalu výrazne skráti a sa môžu v rôznych prehliadačoch líšiť.

    Ale opäť, ak je funkcia alebo požiadavka minimalizovaná, potom je nepravdepodobné, že koncový používateľ pocíti rozdiel.
    Preto, čo použiť, je na rozhodnutí každého.

    © 2024 ermake.ru -- O oprave PC - Informačný portál