Računalniki Windows internet

Časovniki v Javascriptu (setInterval, setTimeout). Primeri funkcije jQuery setTimeout () Javascript preprečuje, da bi več časovnikov hkrati izvajalo setinterval

Časovna omejitev JavaScripta je izvorna funkcija JavaScript, ki izvede del kode po določenem časovnem zamiku (v milisekundah). To je lahko koristno, ko morate prikazati pojavno okno, potem ko je uporabnik nekaj časa preživel na vaši strani. Ali pa želite, da se učinek začne, ko kazalec premaknete nad element šele čez nekaj časa. Na ta način se lahko izognete nenamernemu sprožitvi učinka, če uporabnik po nesreči lebdi.

Preprost primer setTimeout

Za prikaz učinka te funkcije predlagam, da si ogledate naslednjo demonstracijo, v kateri se dve sekundi po kliku gumba prikaže pojavno okno.

Oglejte si demo

Sintaksa

Dokumentacija MDN zagotavlja naslednjo sintakso za setTimeout:

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

  • timeoutID je številčni ID, ki se lahko uporablja v povezavi z clearTimeout () za onemogočanje časovnika;
  • func je funkcija, ki jo je treba izvesti;
  • Koda ( v alternativni sintaksi) - vrstica kode, ki jo je treba izvesti;
  • zamuda - trajanje zamika v milisekundah, po katerem se bo funkcija zagnala. Privzeto je 0.

setTimeout proti window.setTimeout

Zgornja sintaksa uporablja window.setTimeout. Zakaj?

Dejansko sta setTimeout in window.setTimeout praktično ista funkcija. Edina razlika je v tem, da v drugem izrazu uporabljamo metodo setTimeout kot lastnost globalnega objekta okna.

Osebno mislim, da to samo zelo zaplete kodo. Če bi definirali alternativno metodo časovne omejitve JavaScript, ki jo je mogoče najti in vrniti v prednostnem vrstnem redu, bi naleteli na še večje težave.

Za to vadnico se ne želim ukvarjati s predmetom okna, vendar je na splošno odvisno od vas, katero sintakso boste uporabili.

Primeri uporabe

To je lahko ime funkcije:

funkcija explode () (opozorilo ("Bum!");) setTimeout (explode, 2000);

Spremenljivka, ki se nanaša na funkcijo:

var explode = funkcija () (opozorilo ("Bum!");); setTimeout (eksplodirati, 2000);

Ali anonimna funkcija:

setTimeout (funkcija () (opozorilo ("Bum!");), 2000);

  • Takšna koda je slabo zaznana, zato jo bo težko posodobiti ali odpraviti napake;
  • Vključuje uporabo metode eval (), ki bi lahko bila potencialna ranljivost;
  • Ta metoda je počasnejša od drugih, ker mora delovati Tolmač JavaScript.

Upoštevajte tudi, da za testiranje kode uporabljamo metodo opozorila za časovno omejitev JavaScript.

Posredovanje parametrov v setTimout

V prvem ( poleg tega pa navzkrižni brskalnik) posredujemo parametre funkciji povratnega klica, ki se izvaja z setTimeout.

V naslednjem primeru iz matrike greetings izvlečemo naključni pozdrav in ga posredujemo kot parameter funkciji greet (), ki jo izvede setTimeout z 1 sekundno zamudo:

funkcija greet (pozdrav) (console.log (pozdrav);) funkcija getRandom (arr) (vrni arr;) var greetings = ["Pozdravljeni", "Bonjour", "Guten Tag"], randomGreeting = getRandom (pozdrav); setTimeout (funkcija () (pozdrav (randomGreeting);), 1000);

Oglejte si demo

Alternativna metoda

V sintaksi na začetku tega članka je še ena metoda, ki se lahko uporabi za posredovanje parametrov funkciji povratnega klica, ki se izvede s časovno omejitvijo JavaScript. Ta metoda pomeni izhod vseh parametrov, ki sledijo zamudi.

Na podlagi prejšnjega primera dobimo:

setTimeout (pozdrav, 1000, naključniGreeting);

Ta metoda ne bo delovala v IE 9 in starejših, kjer so posredovani parametri nedefinirani. Toda za rešitev tega problema naprej MDN ima poseben polifil.

Povezane težave in "to"

Koda, ki jo izvede setTimeout, se izvaja ločeno od funkcije, ki jo je poklicala. Zaradi tega se soočamo z določenimi težavami, ključno besedo this lahko uporabimo kot rešitev.

var person = (firstName: "Jim", uvod: funkcija () (console.log ("Živjo, jaz" m "+ this.firstName);)); person.introduce (); // Izhodi: Živjo, jaz" m Jim setTimeout (person.introduce, 50); // Izhodi: Živjo, jaz "m undefined

Razlog za ta sklep je v tem, da v prvem primeru to vodi do objekta person, v drugem primeru pa kaže na globalni objekt okna, ki nima lastnosti firstName.

Če se želite znebiti te nedoslednosti, lahko uporabite več metod:

Prisilite, da se to nastavi

To lahko storite z uporabo bind (), metode, ki ustvari novo funkcijo, ki, ko se kliče kot vrednost ključa this, uporablja določeno vrednost. V našem primeru navedena oseba ugovarja. To nam daje kot rezultat:

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

Opomba: Metoda vezave je bila uvedena v ECMAScript 5, kar pomeni, da bo delovala samo v sodobnih brskalnikih. V drugih primerih boste prejeli napako med izvajanjem, ko jo uporabite JavaScript "napaka časovne omejitve funkcije".

Uporabi knjižnico

Številne knjižnice vključujejo vgrajene funkcije, potrebne za rešitev te težave. Na primer, metoda jQuery.proxy (). Vzame funkcijo in vrne novo, v kateri bo vedno uporabil določen kontekst. V našem primeru bo kontekst:

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

Oglejte si demo

Onemogoči časovnik

Vrnjena vrednost setTimeout je številčni ID, ki ga lahko uporabite za onemogočanje časovnika s funkcijo clearTimeout ():

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

Poglejmo v akciji. V naslednjem primeru, če kliknete gumb " Začni odštevanje«, Začne se odštevanje. Ko bo konec, bodo mladički dobili svoje. Toda če pritisnete gumb " Ustavi odštevanje", Časovna omejitev JavaScript bo ustavljena in ponastavljena.

Oglejte si primer

Naj povzamemo

setTimeout je asinhrona funkcija, kar pomeni, da je prejeti klic te funkcije v čakalni vrsti in bo izveden šele po zaključku vseh drugih dejanj na skladu. Ne more se izvajati hkrati z drugimi funkcijami ali ločeno nitjo.

Zelo pomembno je razumeti, kako delujejo časovniki JavaScript. Pogosto se njihovo vedenje ne ujema z našim intuitivnim dojemanjem večnitnosti, in to je posledica dejstva, da dejansko delujejo na isti niti. Oglejmo si štiri funkcije, s katerimi lahko upravljamo časovnike:

  • var id = setTimeout (fn, zamuda); - Ustvari preprost časovnik, ki bo poklical določeno funkcijo po določeni zamudi. Funkcija vrne edinstven ID, s katerim je mogoče začasno zaustaviti časovnik.
  • var id = setInterval (fn, zamuda); - Podobno kot setTimeout, vendar nenehno kliče funkcijo v določenem intervalu (dokler se ne ustavi).
  • clearInterval (id) ;, clearTimeout (id); - Sprejme ID časovnika (ki ga vrne ena od zgoraj opisanih funkcij) in ustavi izvajanje povratnega klica "a.
Glavna ideja, ki jo je treba upoštevati, je, da natančnost obdobja zakasnitve časovnika ni zagotovljena. Za začetek brskalnik izvede vse asinhrone dogodke JavaScript v isti niti (kot so kliki miške ali časovniki) in samo takrat, ko je dogodek na vrsti. To najbolje ponazarja naslednji diagram:

Na tej sliki je veliko informacij, ki jih je treba razumeti, a razumevanje tega vam bo omogočilo globlje razumevanje delovanja asinhronega izvajanja JavaScript. Ta diagram navpično predstavlja čas v milisekundah, modri bloki pa predstavljajo bloke kode JavaScript, ki je bila izvedena. Na primer, prvi blok se v povprečju izvede v 18 ms, klik z miško blokira izvedbo za približno 11 ms itd.

JavaScript lahko izvede samo en kos kode (zaradi enonitne narave izvajanja), od katerih vsak blokira izvajanje drugih asinhronih dogodkov. To pomeni, da ko pride do asinhronega dogodka (kot je klik miške, klic časovnika ali dokončanje zahteve XMLHttp), se ta doda v čakalno vrsto in izvede pozneje (izvedba se seveda razlikuje glede na brskalnik, vendar dogovorimo se, da temu rečemo "čakalna vrsta") ...

Za začetek si predstavljajmo, da se dva časovnika začneta znotraj bloka JavaScript: setTimeout z 10 ms zamudo in setInterval z enako zamudo. Odvisno od tega, kdaj se časovnik zažene, se bo sprožil v trenutku, ko še nismo dokončali prvega bloka kode. Upoštevajte pa, da se ne sproži takoj (ni mogoče zaradi enonitnosti). Namesto tega je odložena funkcija postavljena v čakalno vrsto in se izvede ob naslednjem razpoložljivem času.

Tudi med izvajanjem prvega bloka JavaScript pride do klika miške. Upravljalnika za ta asinhroni dogodek (in je asinhroni, ker ga ne moremo predvideti) v tem trenutku ni mogoče izvesti neposredno, zato tudi vstopi v čakalno vrsto, tako kot časovnik.

Ko se izvede prvi blok kode JavaScript, brskalnik zastavi vprašanje "Kaj čaka na izvedbo?" V tem primeru sta upravljalnik klikov miške in časovnik v stanju čakanja. Brskalnik izbere enega od njih (obravnava klikov) in ga izvede. Časovnik bo počakal na naslednji razpoložljivi del časa v čakalni vrsti za izvedbo.

Upoštevajte, da se med izvajanjem upravljalnika klikov miške sproži prvi intervalni povratni klic. Tako kot povratni klic s časovnikom bo tudi v čakalni vrsti. Upoštevajte pa, da ko se interval znova sproži (medtem ko se izvaja povratni klic časovnika), bo odstranjen iz čakalne vrste. Če bi bili vsi intervalni povratni klic "v čakalni vrsti med izvajanjem velikega dela kode, bi to povzročilo, da bi kup funkcij čakal na klic brez zamud med njihovim dokončanjem. Namesto tega brskalniki ponavadi čakajo, dokler ni več funkcij. čakalno vrsto, preden v čakalno vrsto dodate še eno.

Tako lahko opazimo primer, ko tretja aktivacija intervalnega povratnega klica sovpada s trenutkom, ko se že izvaja. To ponazarja pomembno točko: intervalom ni vseeno, kaj se trenutno izvaja, dodani bodo v čakalno vrsto brez upoštevanja obdobja zamude med izvedbami.

Končno, ko je drugi intervalni povratni klic končan, vidimo, da motorju JavaScript ni ostalo ničesar, kar bi lahko izvedel. To pomeni, da brskalnik znova čaka na nove asinhrone dogodke. To se bo zgodilo pri oznaki 50 ms, ko se bo intervalni povratni klic znova sprožil. Na tej točki ga ne bo nič blokiralo, zato bo deloval takoj.

Oglejmo si primer, ki dobro ponazarja razliko med setTimeout in setInterval.
setTimeout (funkcija () (/ * Nekaj ​​dolgega bloka kode ... * / setTimeout (arguments.callee, 10);), 10); setInterval (funkcija () (/ * Nekaj ​​dolgega bloka kode ... * /), 10);
Ti dve možnosti sta na prvi pogled enakovredni, v resnici pa nista. Koda, ki uporablja setTimeout, bo imela vedno zamik vsaj 10 ms po prejšnjem klicu (lahko je več, nikoli pa ne more biti manj), medtem ko bo koda, ki uporablja setInterval, ponavadi klicana vsakih 10 ms ne glede na to, kdaj je bil izveden prejšnji klic.

Naj povzamemo zgornje:
- motorji JavaScript uporabljajo enonitno okolje in asinhrone dogodke pretvarjajo v čakalno vrsto, ki čaka na izvedbo,
- Funkciji setTimeout in setInterval se v asinhroni kodi izvajata na bistveno različne načine,
- Če časovnika trenutno ni mogoče izvesti, se bo ta zamaknil do naslednje točke izvajanja (ki bo daljša od želene zamude),
- Intervali (setInterval) se lahko izvajajo eden za drugim brez zamud, če njihova izvedba traja dlje od navedene zamude.

Vse to so izjemno pomembne informacije za razvoj. Poznavanje delovanja motorja JavaScript, zlasti z veliko asinhronimi dogodki (kar se pogosto zgodi), postavlja odlične temelje za gradnjo naprednih aplikacij.

  • Od:
  • Registriran: 2014.07.08
  • Objave: 3,896
  • Všeč mi je: 497

Tema: SetTimeOut in SetInterval, kaj je bolje uporabiti v JavaScriptu?

Če želite kodo zagnati večkrat v rednih intervalih, uporabite funkcijo setInterval... Vendar pa ima številne pomanjkljivosti, predvsem različno obnašanje v različnih brskalnikih.

Prva razlika je razlika, ko je časovnik nastavljen za naslednji zagon. Ustvarimo majhen test: izmerili bomo količino časa, ki je pretekel od začetka prejšnjega zagona do njegovega konca.

var d1 = nov datum (), d2 = nov datum (); setInterval (funkcija () (var d = nov datum (); document.body.innerHTML + = (d - d1) + "" + (d - d2) + "
"; // Postavite oznako na začetek funkcije d1 = nov datum (); medtem ko (nov datum () - d1< 200); // ничего не делаем 200 миллисекунд // И в конце функции d2 = new Date(); }, 1000);

Izhod bo informativen od druge vrstice.

V Firefoxu, Operi, Safariju in Chromu bo situacija podobna: prva številka bo približno enaka 1000, druga - 200 manj. Razlika bo le v območju vrednosti. Najmanjša različica v Chromu in Operi.

2 Odgovorite z PunBB (uredil PunBB 08.6.2017 16:45)

  • Od: Moskva, Sovkhoznay 3, apt. 98
  • Registriran: 2014.07.08
  • Objave: 3,896
  • Všeč mi je: 497

Druga razlika, ki je manj opazna in težje reproducirana, včasih pa lahko povzroči veliko težav, je odpornost na spremembe v sistemskem času. Če izvedete naslednji test

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

In po zagonu nastavite sistemski čas za minuto nazaj, nato se v brskalnikih Firefox in Safari spreminjanje številk ustavi in ​​čez minuto se začne znova. Seveda je ročno prevajanje sistemskega časa izjemno redka situacija, vendar je veliko sistemov nastavljenih tako, da samodejno sinhronizirajo čas s strežniki na internetu, zato v nekaterih situacijah tega dejavnika ni mogoče prezreti.

Druga majhna pomanjkljivost funkcije setInterval je, da si morate nekje zapomniti njen identifikator, da bi lahko ustavili njeno delovanje, kar ni vedno priročno.

3 Odgovorite z PunBB

  • Od: Moskva, Sovkhoznay 3, apt. 98
  • Registriran: 2014.07.08
  • Objave: 3,896
  • Všeč mi je: 497

Re: SetTimeOut in SetInterval, kaj je bolje uporabiti v JavaScriptu?

Če se želite znebiti naštetih pomanjkljivosti setInterval, lahko uporabite več setTimeout.

Pomembna alternativa setInterval je rekurzivni setTimeout:

/ ** namesto: var timerId = setInterval (funkcija () (opozorilo ("tick");), 2000); * / var timerId = setTimeout (tick funkcije () (opozorilo ("tick"); timerId = setTimeout (tick, 2000);), 2000);

V zgornji kodi je naslednja izvedba načrtovana takoj za prejšnjim.

Rekurzivni setTimeout je bolj prilagodljiva časovna metoda kot setInterval, saj je čas do naslednje izvedbe mogoče razporediti drugače, odvisno od rezultatov trenutne.

Na primer, imamo storitev, ki vsakih 5 sekund vpraša strežnik za nove podatke. Če je strežnik preobremenjen, lahko interval anketiranja povečate na 10, 20, 60 sekund ... In ga nato vrnete nazaj, ko se vse normalizira.

Če imamo redno naloge, ki obremenjujejo procesor, potem lahko ocenimo čas, porabljen za njihovo izvedbo, in prej ali slej načrtujemo naslednji zagon.

4 Odgovorite z PunBB

  • Od: Moskva, Sovkhoznay 3, apt. 98
  • Registriran: 2014.07.08
  • Objave: 3,896
  • Všeč mi je: 497

Re: SetTimeOut in SetInterval, kaj je bolje uporabiti v JavaScriptu?

Rekurzivni setTimeout zagotavlja premor med klici, setInterval pa ne.

Primerjajmo obe kodi. Prvi uporablja setInterval:

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

Drugi uporablja rekurzivni setTimeout:

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

Z setInterval se bo notranji časovnik sprožil natanko vsakih 100 ms in poklical funkcijo (i):

Resnična pavza med klici func z setInterval je manjša od navedene v kodi!

To je naravno, saj se čas delovanja funkcije nikakor ne upošteva, "poje" del intervala.

Možno je tudi, da se je funkcija func izkazala za bolj zapleteno, kot smo pričakovali in je trajalo dlje kot 100 ms za izvedbo.

V tem primeru bo tolmač počakal, da se funkcija zaključi, nato preveri časovnik, in če je čas za klic setInterval že prišel (ali potekel), se bo naslednji klic zgodil takoj.

Če funkcija traja dlje kot pavza setInterval, se bodo klici zgodili brez prekinitve.

5 Odgovorite z sempai

  • Od: Jeruzalem
  • Registriran: 2015.06.02
  • Objave: 958
  • Všeč mi je: 274

Re: SetTimeOut in SetInterval, kaj je bolje uporabiti v JavaScriptu?

Vse je odvisno od naloge. Na začetku se SetTimeOut uporablja za enkratni zagon časovnika, SetInterval pa za začetek zanke. Toda obe funkciji je mogoče uporabiti za zanko skozi skripte, če se na primer izvajata rekurzivno v funkciji SetTimeOut, bo delovala na praktičen način, podobno kot SetInterval.

Pomanjkljivost SetInterval trenutno je, da ne upošteva časa izvedbe samega skripta (funkcije), in če ga na primer uporabljate za težke zahteve, se bo interval intervala znatno zmanjšal in se lahko razlikujejo v različnih brskalnikih.

Ampak še enkrat, ponavljam, če je funkcija ali zahteva minimizirana, potem končni uporabnik verjetno ne bo občutil razlike.
Zato, kaj uporabiti, se vsak odloči sam.

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

Skoraj vse implementacije JavaScript imajo notranji časovnik razporejanja, ki vam omogoča načrtovanje klica funkcije po določenem časovnem obdobju.

Zlasti ta funkcija je podprta v brskalnikih in v strežniku Node.JS.

setTimeout

sintaksa:

var timerId = setTimeout (funkcija / koda, zamuda [, arg1, arg2 ...])

Opcije:

  • funkcija / koda
    • Funkcija ali vrstica kode za izvedbo.
    • Niz je podprt zaradi združljivosti in ni priporočljiv.
  • zamuda
    • Zakasnitev v milisekundah, 1000 milisekund je enako 1 sekundi.
  • arg1, arg2 ...
    • Argumenti za posredovanje funkciji. Ni podprto v IE9-.
    • Funkcija se bo izvajala po času, določenem v parametru zakasnitve.

Na primer, naslednja koda bo po eni sekundi poklicala opozorilo ("Hello"):

funkcija funkcija ()(opozorilo ("Pozdravljeni");) setTimeout (func, 1000);

Če je prvi argument niz, potem tolmač iz tega niza ustvari anonimno funkcijo.

To pomeni, da tak zapis deluje na popolnoma enak način:

SetTimeout ("opozorilo (" Pozdravljeni ")", 1000);

Namesto tega uporabite anonimne funkcije:

SetTimeout ( funkcija ()(opozorilo ("Pozdravljeni")), 1000);

Funkcijski parametri in kontekst

V vseh sodobnih brskalnikih, ki imajo v mislih IE10, vam setTimeout omogoča, da določite parametre funkcije.

Spodnji primer bo prikazal "Živjo, jaz sem Vasya" povsod, razen IE9-:

funkcija reci Hi (kdo)(opozorilo ("Pozdravljeni, jaz sem" + kdo);) setTimeout (sayHi, 1000, "Vasya");

... Vendar v večini primerov potrebujemo podporo za stari IE in vam ne omogoča podajanja argumentov. Zato je za njihovo posredovanje klic zavit v anonimno funkcijo:

funkcija reci Hi (kdo)(opozorilo ("Pozdravljeni, jaz" + kdo);) setTimeout ( funkcija ()(recimo Živjo ("Vasya")), 1000);

Klicanje prek setTimeout ne prenese konteksta this.

Zlasti klic metode predmeta prek setTimeout bo deloval v globalnem kontekstu. To lahko privede do napačnih rezultatov.

Na primer, po eni sekundi pokličimo user.sayHi ():

funkcija uporabnik (id) funkcija ()(opozorilo (ta .id);); ) var uporabnik = nov uporabnik (12345); setTimeout (user.sayHi, 1000); // pričakovano 12345, vendar bo natisnil "nedefinirano"

Ker bo setTimeout zagnal funkcijo user.sayHi v globalnem kontekstu, prek tega ne bo mogel dostopati do predmeta.

Z drugimi besedami, ta dva klica setTimeout naredita isto stvar:

// (1) ena vrstica setTimeout (user.sayHi, 1000); // (2) ista stvar v dveh vrsticah var func = user.sayHi; setTimeout (funkcija, 1000);

Na srečo je ta problem enostavno rešiti tudi z ustvarjanjem vmesne funkcije:

funkcija uporabnik (id)(ta .id = id; ta .sayHi = funkcija ()(opozorilo (ta .id);); ) var uporabnik = nov uporabnik (12345); setTimeout ( funkcija ()(user.sayHi ();), 1000);

Funkcija ovoja se uporablja za posredovanje argumentov med brskalnikom in shranjevanje konteksta izvajanja.

Prekliči izvedbo

Funkcija setTimeout vrne timerId, ki se lahko uporabi za preklic dejanja.

sintaksa:

ClearTimeout (timerId)

V naslednjem primeru nastavimo časovno omejitev in nato izbrišemo (premislimo). Posledično se nič ne zgodi.

var timerId = setTimeout ( funkcija ()(opozorilo (1)), 1000); clearTimeout (timerId);

setInterval

Metoda setInterval ima sintakso podobno kot setTimeout.

var timerId = setInterval (funkcija / koda, zamuda [, arg1, arg2 ...])

Pomen argumentov je enak. Toda za razliko od setTimeout ne začne izvajati funkcije enkrat, ampak jo redno ponavlja v določenem časovnem intervalu. Izvajanje lahko ustavite tako, da pokličete:

ClearInterval (timerId)

Naslednji primer bo ob zagonu prikazal sporočilo vsaki dve sekundi, dokler ne kliknete gumba Stop:

<vrsta vnosa = "button" onclick = "clearInterval (timer)" vrednost = "(! LANG: Ustavi" > !} <skript> var i = 1; var timer = setInterval ( funkcija ()(opozorilo (i ++)), 2000);skript>

Čakalna vrsta in prekrivanje klicev v setInterval

Če pokličete setInterval (funkcija, zamuda), se funkcija izvede po določenem časovnem intervalu. Ampak tukaj je subtilnost.

Pravzaprav je premor med klici manjši od določenega intervala.

Vzemite na primer setInterval (funkcija () (func (i ++)), 100). Funkcijo izvede vsakih 100 ms in vsakič poveča števec.

Na spodnji sliki je rdeči blok čas izvedbe funkcije func. Čas med blokom je čas med zagoni funkcije in je manjši od nastavljene zakasnitve!

To pomeni, da brskalnik sproži zagon funkcije na vsakih 100 ms, ne da bi upošteval čas izvajanja same funkcije.

Zgodi se, da izvedba funkcije traja dlje kot zamuda. Na primer, funkcija je zapletena in latenca je majhna. Ali pa funkcija vsebuje izjave za opozorilo/potrditev/poziv, ki blokirajo nit izvajanja. V tem primeru se začnejo zanimive stvari.

Če funkcije ni mogoče zagnati, ker je brskalnik zaseden, je postavljena v čakalno vrsto in se izvede takoj, ko je brskalnik prost.

Spodnja slika ponazarja, kaj se dogaja s funkcijo, ki se izvaja dolgo.

Klic funkcije, ki ga sproži setInterval, je dodan v čakalno vrsto in se pojavi takoj, ko je to mogoče:

Drugi zagon funkcije se zgodi takoj po koncu prvega:

Izvedba ni v čakalni vrsti več kot enkrat.

Če izvedba funkcije traja dlje kot več načrtovanih izvedb, bo še vedno enkrat stala v čakalni vrsti. Torej ni "nabiranja" zagonov.

Na spodnji sliki setInterval poskuša izvesti funkcijo v 200 ms in postavi klic v vrsto. Pri 300 ms in 400 ms se časovnik znova prebudi, vendar nič ne preide.

Klicanje setInterval (funkcija, zamuda) ne zagotavlja resnične zamude med izvedbami.

Včasih je dejanska zamuda večja ali manjša od določene. Na splošno ni dejstvo, da bo prišlo do vsaj neke zamude.

Ponovitev ugnezdenega setTimeout

V primerih, ko ni potrebno samo redno ponavljanje, ampak je potrebna zamuda med zagoni, je treba setTimeout znova nastaviti vsakič, ko se funkcija izvede.

Spodaj je primer, ki odda opozorilo z 2-sekundnimi intervali med njimi.

<vrsta vnosa = "button" onclick = "clearTimeout (timer)" vrednost = "(! LANG: Ustavi" > !} <skript> var i = 1; var timer = setTimeout ( zagon funkcije ()(opozorilo (i ++); časovnik = setTimeout (zagon, 2000);), 2000);skript>

Na časovni premici izvedbe bodo določene zamude med zagoni. Ilustracija za 100 ms zamude:

Najmanjša zamuda časovnika

Časovnik brskalnika ima najnižjo možno zamudo. V sodobnih brskalnikih se razlikuje od približno nič do 4 ms. Pri starejših je lahko višja in doseže 15ms.

Po standardu je najmanjša zamuda 4 ms. Torej ni razlike med setTimeout (.., 1) in setTimeout (.., 4).

Obnašanja setTimeout in setInterval brez zakasnitve sta odvisna od brskalnika.

  1. V Operi je setTimeout (.., 0) enak kot setTimeout (.., 4). Izvaja se manj pogosto kot setTimeout (.., 2). To je značilnost tega brskalnika.
  2. V Internet Explorerju ničelna zakasnitev setInterval (.., 0) ne bo uspela. To velja posebej za setInterval, tj. setTimeout (.., 0) deluje dobro.

Dejanska odzivna frekvenca

Lahko se sproži veliko redkeje.V nekaterih primerih zamuda morda ni 4ms, ampak 30ms ali celo 1000ms.

Večina brskalnikov (v prvi vrsti namizje) še naprej izvaja setTimeout/setInterval, tudi če je zavihek neaktiven. Hkrati pa številni (Chrome, FF, IE10) zmanjšajo minimalno frekvenco časovnika na 1-krat na sekundo. Izkazalo se je, da bo časovnik deloval na zavihku "ozadje", vendar redko.

Ko delujejo na baterijo, v prenosnem računalniku - lahko brskalniki tudi znižajo frekvenco, da manj pogosto izvajajo kodo in prihranijo energijo baterije. Po tem je še posebej znan IE. Zmanjšanje je lahko do večkratno, odvisno od nastavitev. Če je obremenitev procesorja pretežka, JavaScript morda ne bo mogel pravočasno obdelati časovnikov. S tem boste preskočili nekaj zagonov setInterval.

Zaključek: voditi bi vas morala frekvenca 4 ms, vendar nanjo ne bi smeli računati.

Izpis intervalov v konzolo Koda, ki šteje intervale med klici, izgleda nekako takole:

var timeMark = nov datum; setTimeout ( funkcija pojdi ()(var diff = nov datum - časovna oznaka; // namesto strani natisnemo drugo zamudo na konzolo konzola .log (razlika); // spomni se časa na samem koncu, // za natančno merjenje zamika med klici timeMark = nov datum; setTimeout (pojdi, 100); ), 100);

Trik setTimeout (func, 0).

Ta trik je vreden vstopa v anale JavaScript vdorov.

Funkcija je zavita v setTimeout (func, 0), če jo želite zagnati po koncu trenutnega skripta.

Bistvo je, da setTimeout nikoli ne izvede funkcije takoj. Načrtuje le njegovo izvedbo. Toda tolmač JavaScript bo začel izvajati načrtovane funkcije šele po izvedbi trenutnega skripta.

Po standardu setTimeout tako ali tako ne more izvesti funkcije z zamudo 0. Kot smo že povedali, je običajno zamuda 4 ms. Toda glavna stvar je, da bo izvedba v vsakem primeru po izvedbi trenutne kode.

Na primer:

rezultat var; funkcija showResult ()(opozorilo (rezultat);) setTimeout (showResult, 0); rezultat = 2 * 2; // bo natisnil 4

Skupaj

Metodi setInterval (func, delay) in setTimeout (func, zamuda) omogočata, da se func izvaja redno / enkrat po zakasnitvi milisekund.

Obe metodi vrneta ID časovnika. Uporablja se za ustavitev izvajanja s klicem clearInterval / clearTimeout.

| | setInterval | setTimeout | || ----------- | ---------- | | Časovni razpored | Klic je strogo na časovniku. Če je tolmač zaseden, en klic vstopi v čakalno vrsto. Čas izvedbe funkcije se ne upošteva, zato je lahko časovni interval od konca enega izvajanja do začetka drugega različen. | Namesto setInterval se uporablja rekurzivni klic setTimeout, kjer je potrebna fiksna pavza med izvedbami. | | Zamuda | Najmanjša zamuda: 4 ms. | Najmanjša zamuda: 4 ms. | | Funkcije brskalnika | Zakasnitev 0 ne deluje v IE | V Operi je ničelna zamuda enaka 4 ms, druge zamude se obravnavajo natančno, vključno z nestandardnimi 1 ms, 2 ms in 3 ms. |

Pri programiranju v skriptnih jezikih je treba občasno ustvariti premor - za nekaj časa prekiniti izvajanje programa in nato nadaljevati z delom. Na primer, v skriptih VBS in PHP so možne naslednje metode:

VBS: wscript.sleep 1500 (ustavi za 1,5 sekunde)

PHP: spanje (10); (ustavite se za 10 sekund)

Med takšnimi premori izvajalni sistem (PHP ali VBS) ne delati nič... Razvijalec, ki poskuša intuitivno uporabiti nekaj takega v Javascriptu, bo neprijetno presenečen. Tipična napaka, ko poskušate ustvariti premor v Javascriptu, izgleda takole:

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

Ali menite, da pri prehodu skozi zanko pride do risanja naslednje številke, vaše setTimeout bo pošteno ustavil delo Javascripta, počakal 0,9 sekunde, dodal zahtevano številko na konec vnosnega polja in nato nadaljeval z delom. Toda v resnici ni: setInterval in setTimeout v Javascriptu zamuja samo dejanje (ali funkcija), ki je navedena v oklepajih. V našem primeru se bo zgodilo naslednje:

  1. i = 1;
  2. odložite dodajanje številke "1" v polje za vnos za 0,9 sekunde;
  3. takoj po nastavitvi tega problema se cikel nadaljuje: i = 2;
  4. odložite dodajanje številke "2" v polje za vnos za 0,9 sekunde;

Takoj pomeni na primer 1 ms (to je neprimerno majhno v primerjavi z 900 ms): cikel bo svoje delo opravil skoraj v trenutku in ustvaril več čakajočih nalog iz istega časa. To pomeni, da bodo vse čakajoče »risalne« naloge zaključene skoraj istočasno, brez premora med dodajanjem novih številk. Cikel se začne; vse zamrzne za 0,9 s; in shirrr - vse številke se streljajo zaporedoma ena za drugo.

In kako se v takem primeru pravilno prijaviti setTimeout? Zapleteno je. Treba je poklicati funkcijo rekurzivno(iz notranjosti funkcije ista funkcija) in da ta proces ni neskončen, nastavite pogoj za zaustavitev (na primer vrednost natisnjene številke):

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

In še ena spremenljivka jaz bo treba inicializirati zunaj funkcije - na primer tako:

Zdaj vse deluje kot mora (čas zakasnitve smo zmanjšali z 0,9 s na 0,4 s). Toda za takšne naloge je bolj logično uporabiti not setTimeout a setInterval(čeprav bi to zahtevalo dve funkciji):

Funkcija besttest () (window.i = 0 window.timer1 = window.setInterval ("draw ()", 400)) funkcija draw () (document.getElementById ("test3"). Vrednost + = ++ i if (i > = 9) clearInterval (window.timer1))

Značilnost metode Javascirpt setInterval dejstvo, da ne mine "samo od sebe", ga je treba ustaviti s posebno metodo clearInterval... In da bi bilo jasno, kaj ustaviti, je nalogi odloženega dejanja dodeljen poseben identifikator - časovnik: window.timer1 = window.setInterval (...).

Opravilom, ustvarjenim z metodo, lahko dodelite tudi identifikatorje setTimeout... Vsi ID-ji časovnika se morajo med seboj razlikovati (enotni v trenutnem oknu brskalnika). Nato lahko v oknu ustvarite več različnih nalog, ki uporabljajo odložena dejanja, in te naloge se bodo izvajale vzporedno (nekako istočasno, če ima računalnik dovolj sredstev), kar je v PHP ali VBS v bistvu nemogoče.

Tukaj je primer strani z več časovniki Javascript, ki se izvajajo hkrati: setinterval.htm (funkcije Javascript v datoteki setinterval.js). Delovanje vseh časovnikov strani (razen menija) lahko ustavite s pritiskom na tipko Esc. Vsi primeri časovnikov se zanašajo na "naravno" (ne abstraktno jaz ++) odštevanje - čas ali razdalja. Vse "ure" so posebej desinhronizirane (zaradi jasnosti). Časovniki, ki temeljijo na razdalji, se uporabljajo v »indikatorju« in v spustnem (spustnem) meniju.

Spustni meni

Naš izvlečni meni je pravzaprav izvlečni (izpod "glave"): med elementi so vrzeli, da vidimo, kako se izvleče. Nepričakovano se je izkazalo, da ne moremo narediti enako gladkega izhoda za sezname različnih dolžin – verjetno zaradi nizke zmogljivosti računalnika (AMD Athlon 999 MHz).

Povsem očitno je, da je za lepoto in harmonijo nujno, da se seznami različnih menijev pojavljajo hkrati. To pomeni, da bi morali daljši seznami izpadati hitreje, krajši - manj. Zdi se, da ga je mogoče izvesti takole:

  1. Skupni čas "odhoda" nastavimo na primer v 200 ms.
  2. Če ima spustni seznam višino 20 px, je očitno, da ga lahko premaknemo za eno slikovno piko navzdol naenkrat za 10 ms - in potem bo čez 200 ms celoten seznam izlezel ven.
  3. Če je spustni meni visok 40 slikovnih pik, ga moramo, da se prilega istočasno, premakniti za eno slikovno piko navzdol v 5 ms.

V skladu s to logiko, če je spustni seznam visok 200 px, ga moramo premakniti za eno slikovno piko naenkrat v 1 ms. Toda ta hitrost ne deluje na našem računalniku - brskalnik preprosto nima časa, da bi v eni milisekundi narisal nov položaj seznama. da. Javascript ima čas za štetje (kaj je treba šteti?), vendar brskalnik (Firefox) nima časa za prikaz. Tipična situacija za splet.

Zato je mogoče čas izstopa iz menija bolj ali manj izenačiti le s pomočjo bergel, kako bo to delovalo na hitrejšem računalniku, pa še ni jasno. Ampak računati moramo na najpočasnejšega, kajne? Algoritem (brez upoštevanja hitrosti računalnika) se izkaže za nekaj takega:

  1. Nastavimo skupni čas odjave seznama: čas = 224 (ms).
  2. Nastavimo minimalni čas za en interval v ciklu: zamuda = 3 (ms).
  3. Nastavite minimalni korak za premikanje seznama: odmik = 1 (px).
  4. Vse to spreminjamo glede na višino seznama: 1) povečamo zakasnitveni (intervalni) čas obratno sorazmerno z višino in premo sorazmerno s skupnim časovnim časom (na višini 224 je koeficient 1); 2) če je višina večja od 40 px, povečajte minimalni korak sorazmerno z višino. Konstanto "40" dobimo empirično za najpočasnejši računalnik. Testi na računalniku Pentium 4 CPU 2,53 GHz so razkrili popolnoma enako številko - 40. Sicer pa časovniki divjajo, seznami ne sledijo tempu.

Zdaj se seznami bolj ali manj širijo. Za bolj ali manj podoben čas. Na strani setinterval.htm.

In tukaj so brki:

Funkcija 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 } } }

Sama funkcija, ki ugnezdene sezname pripelje iz menija, je, kot vidite, zelo preprosta. Ostaja samo, da ga zaženete z nekaj takega, kot je ta vrstica:

Ts.timer1 = setInterval (funkcija () (slide_do (ts, maxtop, offset)), zamuda)

No, preden začnete, samo izračunajte vse te maxtop in offset ter tudi postavite seznam v položaj mintop. Kaj počne "predhodna" funkcija zdrs () Velikost 40 vrstic. In vse skupaj - v datoteki setinterval.js. Da, in to sranje ne bo delovalo brez priloženega slogovnega lista.