Računala Windows Internet

Tajmeri u Javascriptu (setInterval, setTimeout). Primjeri jQuery funkcije setTimeout () Javascript sprječava da više mjerača vremena izvodi setinterval u isto vrijeme

JavaScript timeout je izvorna JavaScript funkcija koja izvršava dio koda nakon određenog vremenskog odgoda (u milisekundama). Ovo može biti korisno kada trebate prikazati skočni prozor nakon što je korisnik proveo neko vrijeme na vašoj stranici. Ili želite da učinak počne kada zadržite pokazivač iznad elementa tek nakon nekog vremena. Na taj način možete izbjeći nenamjerno aktiviranje efekta ako korisnik slučajno pređe preko njega.

Jednostavan primjer setTimeouta

Da biste demonstrirali učinak ove funkcije, predlažem da pogledate sljedeću demonstraciju, u kojoj se skočni prozor pojavljuje dvije sekunde nakon što se klikne na gumb.

Pogledajte demo

Sintaksa

MDN dokumentacija pruža sljedeću sintaksu za setTimeout:

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

  • timeoutID je brojčani id koji se može koristiti zajedno s clearTimeout () za onemogućavanje mjerača vremena;
  • func je funkcija koju treba izvršiti;
  • kod ( u alternativnoj sintaksi) - redak koda koji se izvršava;
  • kašnjenje - trajanje kašnjenja u milisekundama nakon kojeg će se funkcija pokrenuti. Zadana vrijednost je 0.

setTimeout vs window.setTimeout

Gornja sintaksa koristi window.setTimeout. Zašto?

Zapravo, setTimeout i window.setTimeout su praktički ista funkcija. Jedina razlika je u tome što u drugom izrazu koristimo metodu setTimeout kao svojstvo globalnog objekta prozora.

Osobno mislim da to samo uvelike komplicira kod. Ako bismo definirali alternativnu metodu JavaScript timeouta koja se može pronaći i vratiti u prioritetnom redoslijedu, naišli bismo na još veće probleme.

Za ovaj tutorial, ne želim se petljati s objektom prozora, ali općenito na vama je koju ćete sintaksu koristiti.

Primjeri korištenja

Ovo bi mogao biti naziv funkcije:

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

Varijabla koja se odnosi na funkciju:

var explode = function () (upozorenje ("Bum!");); setTimeout (eksplodirati, 2000.);

Ili anonimna funkcija:

setTimeout (funkcija () (upozorenje ("Bum!");), 2000.);

  • Takav se kod slabo percipira i stoga će ga biti teško modernizirati ili otkloniti greške;
  • Uključuje korištenje metode eval (), koja bi mogla biti potencijalna ranjivost;
  • Ova metoda je sporija od ostalih jer treba raditi JavaScript tumač.

Također imajte na umu da koristimo metodu upozorenja za JavaScript timeout za testiranje koda.

Prosljeđivanje parametara u setTimout

U prvom ( osim toga, cross-browser) varijantu, prosljeđujemo parametre funkciji povratnog poziva koja se izvršava sa setTimeout.

U sljedećem primjeru izdvajamo nasumični pozdrav iz niza greetings i prosljeđujemo ga kao parametar funkciji greet (), koju izvršava setTimeout s odgodom od 1 sekunde:

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

Pogledajte demo

Alternativna metoda

U sintaksi na početku ovog članka postoji još jedna metoda koja se može koristiti za prosljeđivanje parametara funkciji povratnog poziva koju izvršava JavaScript timeout. Ova metoda podrazumijeva izlaz svih parametara nakon kašnjenja.

Nadovezujući se na prethodni primjer, dobivamo:

setTimeout (pozdrav, 1000, nasumičniGreeting);

Ova metoda neće raditi u IE 9 i starijim verzijama, gdje su proslijeđeni parametri nedefinirani. Ali za rješavanje ovog problema dalje MDN ima poseban polifil.

Povezani problemi i "ovo"

Kod koji izvršava setTimeout izvodi se odvojeno od funkcije koja ga je pozvala. Zbog toga se suočavamo s određenim problemima, ključna riječ this može poslužiti kao rješenje.

var person = (firstName: "Jim", uvesti: funkciju () (console.log ("Bok, ja" m "+ this.firstName);)); person.introduce (); // Izlazi: Bok, ja" m Jim setTimeout (person.introduce, 50); // Izlazi: Bok, ja sam nedefiniran

Razlog za ovaj zaključak leži u činjenici da u prvom primjeru to vodi do objekta person, a u drugom primjeru ukazuje na globalni objekt prozora, koji nema svojstvo firstName.

Da biste se riješili ove nedosljednosti, možete koristiti nekoliko metoda:

Prisilite da se ovo postavi

To se može učiniti pomoću bind (), metode koja stvara novu funkciju koja, kada se pozove kao vrijednost ključa this, koristi određenu vrijednost. U našem slučaju, navedena osoba prigovara. To nam daje kao rezultat:

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

Napomena: Metoda povezivanja uvedena je u ECMAScript 5, što znači da će raditi samo u modernim preglednicima. U drugima ćete dobiti pogrešku tijekom izvođenja kada je primijenite JavaScript "pogreška isteka funkcije".

Koristite knjižnicu

Mnoge knjižnice uključuju ugrađene funkcije potrebne za rješavanje ovog problema. Na primjer, metoda jQuery.proxy (). Uzima funkciju i vraća novu, u kojoj će uvijek koristiti određeni kontekst. U našem slučaju, kontekst će biti:

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

Pogledajte demo

Onemogući mjerač vremena

Povratna vrijednost setTimeout je brojčani ID koji se može koristiti za onemogućavanje mjerača vremena pomoću funkcije clearTimeout ():

var timer = setTimeout (mojaFunkcija, 3000); clearTimeout (tajmer);

Pogledajmo to na djelu. U sljedećem primjeru, ako kliknete na gumb " Započni odbrojavanje“, Počinje odbrojavanje. Nakon što završi, mačići će dobiti svoje. Ali ako pritisnete tipku " Zaustavite odbrojavanje", Istekanje JavaScripta bit će zaustavljeno i resetirano.

Pogledajte primjer

Hajde da rezimiramo

setTimeout je asinkrona funkcija, što znači da je primljeni poziv ovoj funkciji stavljen u red čekanja i da će se izvršiti tek nakon što se dovrše sve druge radnje na stogu. Ne može se izvoditi istodobno s drugim funkcijama ili zasebnom niti.

Izuzetno je važno razumjeti kako rade JavaScript tajmeri. Često se njihovo ponašanje ne podudara s našom intuitivnom percepcijom višenitnosti, a to je zbog činjenice da oni zapravo rade na istoj niti. Pogledajmo četiri funkcije s kojima možemo kontrolirati mjerače vremena:

  • var id = setTimeout (fn, kašnjenje); - Stvara jednostavan mjerač vremena koji će pozvati navedenu funkciju nakon navedenog odgoda. Funkcija vraća jedinstveni ID pomoću kojeg se mjerač vremena može pauzirati.
  • var id = setInterval (fn, kašnjenje); - Slično kao setTimeout, ali kontinuirano poziva funkciju u navedenom intervalu (dok se ne zaustavi).
  • clearInterval (id) ;, clearTimeout (id); - Prihvaća ID tajmera (koji se vraća jednom od gore opisanih funkcija) i zaustavlja izvršavanje povratnog poziva "a.
Glavna ideja koju treba uzeti u obzir je da preciznost razdoblja kašnjenja timera nije zajamčena. Za početak, preglednik izvršava sve asinkrone JavaScript događaje na istoj niti (kao što su klikovi mišem ili mjerači vremena) i to samo kada je događaj na svom redu. To najbolje ilustruje sljedeći dijagram:

Na ovoj slici ima puno informacija koje treba shvatiti, ali razumijevanje će vam dati dublje razumijevanje kako funkcionira asinkrono izvršavanje JavaScripta. Ovaj dijagram okomito predstavlja vrijeme u milisekundama, a plavi blokovi predstavljaju blokove JavaScript koda koji je izvršen. Na primjer, prvi blok se izvršava u prosjeku za 18 ms, klik mišem blokira izvršenje za oko 11 ms, itd.

JavaScript može izvršiti samo jedan dio koda (zbog jednonitne prirode izvršenja), od kojih svaki blokira izvođenje drugih asinkronih događaja. To znači da kada dođe do asinkronog događaja (kao što je klik mišem, poziv timera ili završetak XMLHttp zahtjeva), on se dodaje u red čekanja i izvršava kasnije (naravno, implementacija varira ovisno o pregledniku, ali dogovorimo se da ovo nazovemo "red") ...

Za početak, zamislimo da dva mjerača vremena počinju unutar JavaScript bloka: setTimeout s kašnjenjem od 10 ms i setInterval s istim kašnjenjem. Ovisno o tome kada se timer pokrene, aktivirat će se u trenutku kada još nismo dovršili prvi blok koda. Međutim, imajte na umu da se ne aktivira odmah (nije moguće zbog jednonitnog rada). Umjesto toga, odgođena funkcija stavlja se u red čekanja i izvršava se u sljedeće dostupno vrijeme.

Također, tijekom izvođenja prvog JavaScript bloka dolazi do klika mišem. Rukovalac za ovaj asinkroni događaj (a on je asinkroni, jer ga ne možemo predvidjeti) u ovom trenutku ne može se izvršiti izravno, pa također ulazi u red čekanja, kao i timer.

Nakon što se izvrši prvi blok JavaScript koda, preglednik postavlja pitanje "Što čeka izvršenje?" U ovom slučaju, rukovatelj klikovima mišem i mjerač vremena su u stanju čekanja. Preglednik odabire jedan od njih (upravljač klikovima) i izvršava ga. Mjerač vremena će pričekati sljedeći raspoloživi dio vremena u redu za izvršavanje.

Imajte na umu da se aktivira prvi intervalni povratni poziv dok se rukovatelj klikovima mišem izvršava. Baš kao i timer-callback, bit će u redu. Međutim, imajte na umu da će se interval ponovno aktivirati (dok je timer-callback pokrenut) iz reda čekanja. Kad bi svi intervalni povratni pozivi "bili u redu dok se veliki dio koda izvršavao, to bi rezultiralo gomilom funkcija koje čekaju da budu pozvane bez kašnjenja između njihovog završetka. Umjesto toga, preglednici obično čekaju dok ne ostane nijedna funkcija. čekati u redu prije nego što dodate još jedan u red čekanja.

Dakle, možemo promatrati slučaj kada se treća aktivacija intervalnog povratnog poziva poklopi s trenutkom kada se već izvršava. Ovo ilustrira važnu točku: intervali ne brinu o tome što se trenutno izvodi, oni će biti dodani u red bez uzimanja u obzir razdoblja kašnjenja između izvršenja.

Konačno, nakon završetka drugog intervalnog povratnog poziva, vidimo da nema više ništa za JavaScript motor za izvršenje. To znači da preglednik ponovno čeka nove asinkrone događaje. To će se dogoditi na oznaci od 50 ms, gdje će se ponovno aktivirati intervalni povratni poziv. U ovom trenutku neće ga moći ništa blokirati, tako da će odmah proraditi.

Pogledajmo primjer koji dobro ilustrira razliku između setTimeout i setInterval.
setTimeout (funkcija () (/ * Neki dugi blok koda ... * / setTimeout (arguments.callee, 10);), 10); setInterval (funkcija () (/ * Neki dugi blok koda ... * /), 10);
Ove dvije opcije su na prvi pogled jednake, ali u stvarnosti nisu. Kod koji koristi setTimeout uvijek će imati kašnjenje od najmanje 10 ms nakon prethodnog poziva (može biti više, ali nikad manje), dok će kod koji koristi setInterval biti pozvan svakih 10 ms bez obzira na to kada je prethodni poziv izvršen.

Da ponovimo gore navedeno:
- JavaScript motori koriste okruženje s jednim niti, pretvarajući asinkrone događaje u red čekanja na izvršenje,
- Funkcije setTimeout i setInterval izvode se na bitno različite načine u asinkronom kodu,
- Ako se timer ne može izvršiti u ovom trenutku, bit će odgođen do sljedeće točke izvršenja (koja će biti duža od željene odgode),
- Intervali (setInterval) mogu se izvršavati jedan za drugim bez kašnjenja ako njihovo izvođenje traje dulje od navedenog odgoda.

Sve su to iznimno važne informacije za razvoj. Poznavanje načina rada JavaScript motora, posebno s puno asinkronih događaja (što se često događa), postavlja izvrstan temelj za izgradnju naprednih aplikacija.

  • Iz:
  • Registriran: 2014.07.08
  • Postovi: 3,896
  • Sviđa mi se: 497

Tema: SetTimeOut i SetInterval, što je bolje koristiti u JavaScriptu?

Za pokretanje koda više puta u redovitim intervalima, koristite funkciju setInterval... Međutim, ima niz nedostataka, uglavnom različito ponašanje u različitim preglednicima.

Prva razlika je razlika kada je mjerač vremena postavljen za sljedeći početak. Napravimo mali test: izmjerit ćemo koliko je vremena proteklo od početka prethodnog pokretanja i od njegovog kraja.

var d1 = novi datum (), d2 = novi datum (); setInterval (funkcija () (var d = novi datum (); document.body.innerHTML + = (d - d1) + "" + (d - d2) + "
"; // Stavite oznaku na početak funkcije d1 = novi datum (); dok (novi datum () - d1< 200); // ничего не делаем 200 миллисекунд // И в конце функции d2 = new Date(); }, 1000);

Ispis će biti informativan počevši od drugog retka.

U Firefoxu, Operi, Safariju i Chromeu situacija će biti slična: prvi broj će biti približno jednak 1000, drugi - 200 manje. Razlika će biti samo u rasponu vrijednosti. Najmanja varijacija u Chromeu i Operi.

2 Odgovorite od strane PunBB (uredio PunBB 08.6.2017. 16:45)

  • Iz: Moskva, Sovkhoznay 3, apt. 98
  • Registriran: 2014.07.08
  • Postovi: 3,896
  • Sviđa mi se: 497

Druga razlika koja je manje uočljiva i teže reproducirana, ali ponekad može uzrokovati mnogo problema, je otpornost na promjene u vremenu sustava. Ako pokrenete sljedeći test

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

I nakon pokretanja, vratite sistemsko vrijeme za minutu unatrag, zatim u preglednicima Firefox i Safari promjena brojeva će pauzirati, a nakon minute će ponovno početi. Naravno, ručni prijevod sistemskog vremena je iznimno rijetka situacija, ali mnogi sustavi su konfigurirani za automatsku sinkronizaciju vremena s poslužiteljima na Internetu, pa se u nekim situacijama ovaj faktor ne može zanemariti.

Još jedan mali nedostatak funkcije setInterval je to što da biste mogli zaustaviti njezino djelovanje, morate negdje zapamtiti njen identifikator, što nije uvijek prikladno.

3 Odgovorite od strane PunBB

  • Iz: Moskva, Sovkhoznay 3, apt. 98
  • Registriran: 2014.07.08
  • Postovi: 3,896
  • Sviđa mi se: 497

Re: SetTimeOut i SetInterval, što je bolje koristiti u JavaScriptu?

Da biste se riješili navedenih nedostataka setInterval, možete koristiti višestruki setTimeout.

Važna alternativa setIntervalu je rekurzivni setTimeout:

/ ** umjesto: var timerId = setInterval (funkcija () (upozorenje ("tick");), 2000.); * / var timerId = setTimeout (kvačica funkcije () (upozorenje ("tick"); timerId = setTimeout (tick, 2000);), 2000);

U kodu iznad, sljedeće izvršenje je zakazano odmah nakon prethodnog.

Rekurzivni setTimeout je fleksibilnija metoda mjerenja vremena od setInterval, budući da se vrijeme do sljedećeg izvršenja može drugačije rasporediti, ovisno o rezultatima trenutnog.

Na primjer, imamo uslugu koja proziva poslužitelj za nove podatke svakih 5 sekundi. Ako je poslužitelj preopterećen, možete povećati interval prozivanja na 10, 20, 60 sekundi... I onda ga vratiti kad se sve normalizira.

Ako redovito imamo zadatke koji opterećuju procesor, tada možemo procijeniti vrijeme utrošeno na njihovo izvršavanje i zakazati sljedeće pokretanje prije ili kasnije.

4 Odgovorite od strane PunBB

  • Iz: Moskva, Sovkhoznay 3, apt. 98
  • Registriran: 2014.07.08
  • Postovi: 3,896
  • Sviđa mi se: 497

Re: SetTimeOut i SetInterval, što je bolje koristiti u JavaScriptu?

Rekurzivni setTimeout jamči pauzu između poziva, setInterval ne.

Usporedimo dva koda. Prvi koristi setInterval:

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

Drugi koristi rekurzivni setTimeout:

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

Uz setInterval, interni mjerač vremena će se aktivirati točno svakih 100 ms i pozvati funkciju (i):

Prava pauza između func poziva sa setInterval manja je od navedenog u kodu!

To je prirodno, jer se vrijeme rada funkcije ni na koji način ne uzima u obzir, "jede" dio intervala.

Također je moguće da se func pokazao kompliciranijim nego što smo očekivali i da je trebalo više od 100 ms da se izvrši.

U tom slučaju, tumač će pričekati da se funkcija dovrši, zatim će provjeriti mjerač vremena, a ako je vrijeme za pozivanje setInterval već došlo (ili prošlo), tada će se odmah dogoditi sljedeći poziv.

Ako funkcija traje dulje od pauze setInterval, tada će se pozivi odvijati bez prekida.

5 Odgovorite od strane sempai

  • Iz: Jeruzalem
  • Registriran: 2015.06.02
  • Postovi: 958
  • Sviđa mi se: 274

Re: SetTimeOut i SetInterval, što je bolje koristiti u JavaScriptu?

Sve ovisi o zadatku. U početku se SetTimeOut koristi za pokretanje timera jednom, a SetInterval za pokretanje petlje. Ali obje se funkcije mogu koristiti za petlju kroz skripte, ako se, na primjer, izvode rekurzivno u funkciji SetTimeOut, djelovat će na praktičan način slično SetIntervalu.

Nedostatak SetIntervala u ovom trenutku je što ne uzima u obzir vrijeme izvršavanja same skripte (funkcije), a ako ga, na primjer, koristite za teške zahtjeve, tada će se vrijeme intervala značajno smanjiti, a mogu se razlikovati u različitim preglednicima.

Ali opet, ponavljam, ako je funkcija ili zahtjev minimiziran, tada krajnji korisnik vjerojatno neće osjetiti razliku.
Stoga, što koristiti, svatko odlučuje za sebe.

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

Gotovo sve implementacije JavaScripta imaju interni mjerač vremena za zakazivanje koji vam omogućuje da zakažete poziv funkcije nakon određenog vremenskog razdoblja.

Konkretno, ova je značajka podržana u preglednicima i na Node.JS poslužitelju.

setTimeout

Sintaksa:

var timerId = setTimeout (funkcija / kod, kašnjenje [, arg1, arg2 ...])

Opcije:

  • funkcija / kod
    • Funkcija ili redak koda za izvršenje.
    • Niz je podržan radi kompatibilnosti i ne preporučuje se.
  • odgoditi
    • Kašnjenje u milisekundama, 1000 milisekundi jednako je 1 sekundi.
  • arg1, arg2 ...
    • Argumenti za prosljeđivanje funkciji. Nije podržano u IE9-.
    • Funkcija će se izvršiti nakon vremena navedenog u parametru kašnjenja.

Na primjer, sljedeći će kod pozvati upozorenje ("Halo") nakon jedne sekunde:

funkcija funkcija ()(upozorenje ("Zdravo");) setTimeout (func, 1000);

Ako je prvi argument niz, onda interpretator stvara anonimnu funkciju iz tog niza.

Odnosno, takav zapis radi na potpuno isti način:

SetTimeout ("upozorenje (" Pozdrav ")", 1000);

Umjesto toga upotrijebite anonimne funkcije:

SetTimeout ( funkcija ()(upozorenje ("Zdravo")), 1000);

Parametri funkcije i kontekst

U svim modernim preglednicima, s IE10 na umu, setTimeout vam omogućuje da odredite parametre funkcije.

Primjer u nastavku će prikazati "Bok, ja sam Vasya" svugdje osim IE9-:

funkcija reciHi (tko)(upozorenje ("Zdravo, ja sam" + tko);) setTimeout (sayHi, 1000, "Vasya");

... Međutim, u većini slučajeva trebamo podršku za stari IE, a on vam ne dopušta navođenje argumenata. Stoga, kako bi ih proslijedio, poziv je omotan u anonimnu funkciju:

funkcija reciHi (tko)(upozorenje ("Zdravo, ja" + tko);) setTimeout ( funkcija ()(sayHi ("Vasya")), 1000);

Pozivanje kroz setTimeout ne prolazi kroz ovaj kontekst.

Konkretno, pozivanje metode objekta putem setTimeout će raditi u globalnom kontekstu. To može dovesti do netočnih rezultata.

Na primjer, nazovimo user.sayHi () nakon jedne sekunde:

funkcija korisnik (id) funkcija ()(upozorenje (ovaj .id);); ) var korisnik = novi korisnik (12345); setTimeout (user.sayHi, 1000); // očekuje se 12345, ali će ispisati "nedefinirano"

Budući da će setTimeout pokrenuti funkciju user.sayHi u globalnom kontekstu, neće moći pristupiti objektu putem ovoga.

Drugim riječima, ova dva poziva za setTimeout rade istu stvar:

// (1) jedan red setTimeout (user.sayHi, 1000); // (2) ista stvar u dva retka var func = user.sayHi; setTimeout (funkcija, 1000);

Srećom, ovaj se problem također lako rješava stvaranjem međufunkcije:

funkcija korisnik (id)(ovaj .id = id; ovaj .sayHi = funkcija ()(upozorenje (ovaj .id);); ) var korisnik = novi korisnik (12345); setTimeout ( funkcija ()(user.sayHi ();), 1000);

Funkcija omota koristi se za prosljeđivanje argumenata preko preglednika i pohranjivanje konteksta izvršavanja.

Otkaži izvršenje

Funkcija setTimeout vraća timerId koji se može koristiti za otkazivanje radnje.

Sintaksa:

ClearTimeout (timerId)

U sljedećem primjeru postavljamo timeout, a zatim brišemo (predomislimo se). Kao rezultat toga, ništa se ne događa.

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

setInterval

Metoda setInterval ima sintaksu sličnu setTimeoutu.

var timerId = setInterval (funkcija / kod, kašnjenje [, arg1, arg2 ...])

Značenje argumenata je isto. Ali, za razliku od setTimeouta, on počinje izvršavanje funkcije ne jednom, već je redovito ponavlja u određenom vremenskom intervalu. Izvršenje možete zaustaviti pozivom:

ClearInterval (timerId)

Sljedeći primjer, pri pokretanju, prikazat će poruku svake dvije sekunde dok ne kliknete na gumb Stop:

<vrsta unosa = "button" onclick = "clearInterval (timer)" vrijednost = "(! LANG: Stop" > !} <skripta> var i = 1; var timer = setInterval ( funkcija ()(uzbuna (i ++)), 2000.);skripta>

Stavljanje u red i preklapanje poziva u setInterval

Pozivanje setInterval (funkcija, kašnjenje) stavlja funkciju koja se izvršava nakon navedenog vremenskog intervala. Ali ovdje postoji jedna suptilnost.

Zapravo, pauza između poziva manja je od navedenog intervala.

Na primjer, uzmite setInterval (funkcija () (func (i ++)), 100). Izvršava funkciju svakih 100ms, svaki put povećavajući brojač.

Na slici ispod, crveni blok je vrijeme izvršenja funkcije. Vrijeme između bloka je vrijeme između pokretanja funkcije i manje je od zadane odgode!

Odnosno, preglednik pokreće pokretanje funkcije uredno svakih 100 ms, ne uzimajući u obzir vrijeme izvršavanja same funkcije.

Događa se da izvršavanje funkcije traje dulje od kašnjenja. Na primjer, funkcija je složena i latencija je mala. Ili funkcija sadrži naredbe upozorenja/potvrde/prompta koje blokiraju nit izvršenja. U ovom slučaju počinju zanimljive stvari.

Ako se funkcija ne može pokrenuti jer je preglednik zauzet, stavlja se u red čekanja i izvršava se čim se preglednik oslobodi.

Slika ispod ilustrira što se događa za funkciju kojoj je potrebno dugo vremena da se izvrši.

Poziv funkcije koji je pokrenuo setInterval dodaje se u red čekanja i događa se odmah kada to postane moguće:

Drugo pokretanje funkcije događa se odmah nakon završetka prvog:

Izvršenje se ne stavlja u red čekanja više od jednom.

Ako izvršenje funkcije traje dulje od nekoliko zakazanih izvršenja, ona će i dalje jednom stajati u redu čekanja. Dakle, nema "nagomilavanja" lansiranja.

Na slici ispod, setInterval pokušava izvršiti funkciju za 200 ms i stavlja poziv u red. Na 300 ms i 400 ms mjerač vremena se ponovno budi, ali ništa ne prolazi.

Pozivanje setInterval (funkcija, kašnjenje) ne jamči stvarno kašnjenje između izvršenja.

Postoje slučajevi kada je stvarno kašnjenje veće ili manje od navedenog. Općenito, nije činjenica da će doći do barem nekakvog kašnjenja.

Ponavljanje ugniježđenog setTimeouta

U slučajevima kada nije potrebno samo redovito ponavljanje, već je potrebno kašnjenje između pokretanja, setTimeout treba ponovno postaviti svaki put kada se funkcija izvrši.

Ispod je primjer koji emitira upozorenje s razmakom od 2 sekunde između njih.

<vrsta unosa = "button" onclick = "clearTimeout (timer)" vrijednost = "(! LANG: Stop" > !} <skripta> var i = 1; var timer = setTimeout ( pokretanje funkcije ()(upozorenje (i ++); timer = setTimeout (run, 2000);), 2000);skripta>

Na vremenskoj traci izvršenja bit će fiksna kašnjenja između pokretanja. Ilustracija za kašnjenje od 100 ms:

Minimalno kašnjenje timera

Tajmer preglednika ima najmanju moguću latenciju. Ona varira od oko nula do 4 ms u modernim preglednicima. Kod starijih može biti veći i doseći 15ms.

Prema standardu, minimalno kašnjenje je 4 ms. Dakle, nema razlike između setTimeout (.., 1) i setTimeout (.., 4).

Ponašanja setTimeout i setInterval nulte kašnjenja su specifična za preglednik.

  1. U Operi je setTimeout (.., 0) isto što i setTimeout (.., 4). Pokreće se rjeđe od setTimeout (.., 2). Ovo je značajka ovog preglednika.
  2. U Internet Exploreru, nulta kašnjenja setInterval (.., 0) neće uspjeti. Ovo se posebno odnosi na setInterval, tj. setTimeout (.., 0) radi dobro.

Stvarna frekvencija odgovora

Može se aktivirati mnogo rjeđe.U nekim slučajevima kašnjenje ne mora biti 4ms, već 30ms ili čak 1000ms.

Većina preglednika (na prvom mjestu stolna računala) nastavlja izvršavati setTimeout / setInterval čak i ako je kartica neaktivna. U isto vrijeme, određeni broj njih (Chrome, FF, IE10) smanjuje minimalnu frekvenciju timera, na 1 put u sekundi. Ispada da će mjerač vremena raditi na kartici "pozadina", ali rijetko.

Kada rade na bateriju, u prijenosnom računalu - preglednici također mogu sniziti frekvenciju kako bi rjeđe izvršavali kod i uštedjeli energiju baterije. IE je posebno poznat po tome. Smanjenje može biti i do nekoliko puta, ovisno o postavkama. Ako je opterećenje procesora previše, JavaScript možda neće moći obraditi mjerače vremena na vrijeme. Ovo će preskočiti neke od pokretanja setInterval.

Zaključak: trebali biste se voditi frekvencijom od 4ms, ali ne biste trebali računati na nju.

Izlaz intervala na konzolu Kod koji broji intervale između poziva izgleda otprilike ovako:

var timeMark = novi datum; setTimeout ( funkcija idi ()(var diff = novi datum - oznaka vremena; // ispisati još jedno kašnjenje na konzolu umjesto stranice konzola .log (razl.); // zapamti vrijeme na samom kraju, // za točno mjerenje kašnjenja između poziva timeMark = novi datum; setTimeout (kreni, 100); ), 100 );

Trik setTimeout (func, 0).

Ovaj trik je dostojan ulaska u anale JavaScript hakova.

Funkcija je omotana u setTimeout (func, 0) ako je želite pokrenuti nakon završetka trenutne skripte.

Poanta je da setTimeout nikada ne izvršava funkciju odmah. On samo planira njegovu provedbu. Ali JavaScript interpreter će početi izvršavati planirane funkcije tek nakon izvršenja trenutne skripte.

Po standardu, setTimeout ionako ne može izvršiti funkciju s kašnjenjem od 0. Kao što smo ranije rekli, obično će kašnjenje biti 4 ms. Ali glavna stvar ovdje je da će izvršenje u svakom slučaju biti nakon izvršenja trenutnog koda.

Na primjer:

var rezultat; funkcija showResult ()(upozorenje (rezultat);) setTimeout (showResult, 0); rezultat = 2 * 2; // će ispisati 4

Ukupno

Metode setInterval (func, kašnjenje) i setTimeout (func, kašnjenje) omogućuju redovito pokretanje funkcije / jednom nakon odgode milisekundi.

Obje metode vraćaju ID tajmera. Koristi se za zaustavljanje izvršavanja pozivanjem clearInterval / clearTimeout.

| | setInterval | setTimeout | || ----------- | ---------- | | Vrijeme | Postoji poziv strogo na tajmeru. Ako je tumač zauzet, jedan poziv ulazi u red čekanja. Vrijeme izvršenja funkcije se ne uzima u obzir, pa vremenski interval od kraja jednog pokretanja do početka drugog može biti različit. | Umjesto setInterval koristi se rekurzivni poziv setTimeout gdje je potrebna fiksna pauza između izvršenja. | | Odgoda | Minimalno kašnjenje: 4ms. | Minimalno kašnjenje: 4ms. | | Značajke preglednika | Odgoda 0 ne radi u IE | U Operi, nulta latencija je ekvivalentna 4 ms, ostala kašnjenja se obrađuju točno, uključujući nestandardne 1 ms, 2 ms i 3 ms. |

U programiranju u skriptnim jezicima povremeno je potrebno napraviti pauzu - obustaviti izvršavanje programa na neko vrijeme, a zatim nastaviti s radom. Na primjer, u VBS i PHP skriptama moguće su sljedeće metode:

VBS: wscript.sleep 1500 (zaustavite se na 1,5 sekunde)

PHP: spavanje (10); (zaustavite se 10 sekundi)

Tijekom takvih pauza, runtime sustav (PHP ili VBS) ne radeći ništa... Programer koji pokušava intuitivno koristiti nešto poput ovoga u Javascriptu bit će neugodno iznenađen. Tipična pogreška pri pokušaju stvaranja pauze u Javascriptu izgleda ovako:

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

Mislite li da kada, prilikom prolaska kroz petlju, dođe do crtanja sljedeće znamenke, vaše setTimeoutće iskreno zaustaviti rad Javascripta, pričekati 0,9 sekundi, dodati traženi broj na kraj polja za unos, a zatim nastaviti s radom. Ali zapravo nije: setInterval i setTimeout u Javascriptu odgađa se samo radnja (ili funkcija) navedena u zagradama. U našem primjeru dogodit će se sljedeće:

  1. i = 1;
  2. odgoditi dodavanje broja "1" u polje za unos za 0,9 sekundi;
  3. odmah nakon postavljanja ovog problema, ciklus se nastavlja: i = 2;
  4. odgoditi dodavanje broja "2" u polje za unos za 0,9 sekundi;

Odmah znači, na primjer, 1 ms (to jest, neusporedivo malo, u usporedbi s 900 ms): ciklus će obaviti svoj posao gotovo trenutno, stvarajući nekoliko zadataka na čekanju iz istog trenutka. To znači da će svi zadaci "crtanja" na čekanju biti dovršeni gotovo u isto vrijeme, bez pauza između dodavanja novih brojeva. Ciklus počinje; sve se zamrzne 0,9 s; i shirrr - pucaju se svi brojevi redom jedan za drugim.

I kako je, u takvom slučaju, ispravno primijeniti setTimeout? Komplicirano je. Treba pozvati funkciju rekurzivno(iznutra funkcije, ista funkcija), i da ovaj proces ne bude beskonačan, postavite uvjet zaustavljanja (na primjer, vrijednost ispisanog broja):

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

I još jedna varijabla i morat će se inicijalizirati izvan funkcije - na primjer, ovako:

Sada sve radi kako treba (smanjili smo vrijeme kašnjenja sa 0,9 s na 0,4 s). Ali za takve je zadatke logičnije koristiti ne setTimeout a setInterval(iako bi to zahtijevale dvije funkcije):

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

Značajka metode Javascirpt setInterval to što ne prolazi "samo od sebe", mora se zaustaviti posebnom metodom clearInterval... A da bi bilo jasno što zaustaviti, zadatku odgođene akcije dodijeljen je poseban identifikator - mjerač vremena: window.timer1 = window.setInterval (...).

Identifikatori se također mogu dodijeliti zadacima kreiranim metodom setTimeout... Svi ID-ovi mjerača vremena moraju se međusobno razlikovati (jedinstveni unutar trenutnog prozora preglednika). Zatim možete kreirati nekoliko različitih zadataka u prozoru koji koriste odgođene radnje, a ti zadaci će se izvoditi paralelno (nešto kao istovremeno, ako računalo ima dovoljno resursa), što je u osnovi nemoguće u PHP-u ili VBS-u.

Evo primjera stranice s više Javascript mjerača vremena koji rade u isto vrijeme: setinterval.htm (Javascript funkcije u datoteci setinterval.js). Rad svih mjerača vremena stranica (osim izbornika) može se zaustaviti pritiskom na tipku Esc. Svi primjeri mjerača vremena oslanjaju se na "prirodno" (ne apstraktno ja ++) odbrojavanje - vrijeme ili udaljenost. Svi "satovi" su posebno desinkronizirani (radi jasnoće). Tajmeri temeljeni na udaljenosti koriste se u “indikatoru” iu padajućem (padajućem) izborniku.

Padajući izbornik

Naš izvlačni izbornik je zapravo izvlačenje (ispod "zaglavlja"): postoje praznine između elemenata da se vidi kako se izvlači. Neočekivano se pokazalo da ne možemo napraviti jednako gladak izlaz za liste različitih duljina - vjerojatno zbog niske performanse računala (AMD Athlon 999 MHz).

Sasvim je očito da je za ljepotu i sklad potrebno da se liste različitih stavki na jelovniku pojavljuju u isto vrijeme. Odnosno, dulje liste trebale bi ispadati brže, kraće - nižom stopom. Čini se da se to može implementirati ovako:

  1. Ukupno vrijeme "odlaska" postavljamo na primjer u 200 ms.
  2. Ako padajući popis ima visinu od 20 px, očito je da ga možemo pomicati za jedan piksel prema dolje za 10 ms - a onda će za 200 ms cijeli popis ispuzati.
  3. Ako je padajući izbornik visok 40px, da bi stao u isto vrijeme, moramo ga pomicati jedan po piksel prema dolje za 5ms.

Prema ovoj logici, ako je padajući popis visok 200 px, moramo ga pomicati jedan po jedan piksel prema dolje za 1 ms. Ali ova brzina ne radi na našem računalu - preglednik jednostavno nema vremena nacrtati novu poziciju popisa u jednoj milisekundi. Da. Javascript ima vremena za brojanje (što se tu ima za brojati?), ali preglednik (Firefox) nema vremena za prikaz. Tipična situacija za web.

Stoga je vrijeme izlaska iz izbornika moguće manje-više izjednačiti samo uz pomoć štaka, a kako će to funkcionirati na bržem računalu, još je nejasno. Ali moramo računati na najsporijeg, zar ne? Algoritam (bez uzimanja u obzir brzine računala) ispada otprilike ovako:

  1. Postavljamo ukupno vrijeme odjave liste: vrijeme = 224 (ms).
  2. Postavljamo minimalno vrijeme za jedan interval u ciklusu: kašnjenje = 3 (ms).
  3. Postavite minimalni korak za pomicanje popisa: pomak = 1 (px).
  4. Sve to mijenjamo ovisno o visini liste: 1) povećavamo vrijeme kašnjenja (interval) obrnuto proporcionalno visini i izravno proporcionalno ukupnom vremenu (na visini 224 koeficijent je 1); 2) ako je visina veća od 40 px, povećajte minimalni korak proporcionalno visini. Konstanta "40" dobiva se empirijski za najsporije računalo. Testovi na Pentium 4 CPU 2,53GHz računalu otkrili su točno isti broj - 40. Inače, mjerači vremena podivljaju, popisi ne idu u korak.

Sada se popisi više-manje kreću. Za manje-više slično vrijeme. Na stranici setinterval.htm.

A evo Bru-brkova:

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, koja izvlači ugniježđene liste iz izbornika, je, kao što vidite, vrlo jednostavna. Ostaje samo pokrenuti ga s nečim poput ove linije:

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

Pa, prije početka, samo izračunajte sve ove maxtop i offset, a također stavite popis u mintop poziciju. Što radi "preliminarna" funkcija slajd () Veličina 40 redaka. I sve zajedno - u datoteci setinterval.js. Da, i ovo sranje neće raditi bez priložene tablice stilova.