Ați trebuit vreodată să faceți o listă, dar operația a durat o perioadă semnificativă de timp? Ați avut vreodată un accident de program deoarece o operație a folosit prea multă memorie? Acest lucru mi sa întâmplat când am încercat să pun în aplicare o funcție care generează numere prime.
Generarea de prime numere de până la un milion a durat mult mai mult decât mi-ar plăcea. Dar generarea de numere de până la 10 milioane a fost imposibilă. Programul meu s-ar prăbuși sau doar ar fi atârnat. Eu deja folosesc sita Eratosthenes, care ar trebui să fie mai eficientă la generarea primelor decât abordarea forței brute.
Dacă vă aflați într-o situație similară, puteți încerca să folosiți un alt algoritm. Există algoritmi de căutare și sortare care funcționează mai bine pe intrări mai mari. Dezavantajul este că acești algoritmi pot fi mai greu de înțeles imediat. O altă opțiune este folosirea unui limbaj de programare diferit.
O limbă compilată poate fi capabilă să proceseze mai rapid codul. Dar folosirea unei alte limbi poate să nu fie practică. De asemenea, puteți încerca utilizarea mai multor fire. Încă o dată, este posibil să nu fie practică, deoarece limba dvs. de programare ar trebui să sprijine acest lucru.
Din fericire, cu JavaScript, există o altă opțiune. Dacă aveți o sarcină computațional intensivă, puteți utiliza iteratori și generatoare pentru a obține o anumită eficiență. Iteratoarele sunt proprietatea anumitor colecții JavaScript.
Iteratoarele îmbunătățesc eficiența, permițându-vă să consumați articolele dintr-o listă la un moment dat ca și cum ar fi un flux. Generatoarele sunt un tip special de funcție care poate întrerupe execuția. Invocarea unui generator vă permite să produceți date într-o singură bucată, fără a mai fi necesar să le stocați mai întâi într-o listă.
În primul rând, să examinăm diferitele moduri prin care puteți să vă conectați prin colecțiile din JavaScript. O buclă a formei pentru (inițial; condiție; pas) ...
va executa comenzile în corpul său de un anumit număr de ori. În mod similar, o buclă de timp va executa comenzile din corpul său atâta timp cât condiția este adevărată.
Puteți utiliza aceste bucle pentru a traversa o listă prin incrementarea unei variabile index la fiecare iterație. O iterație este o execuție a corpului unei bucla. Aceste bucle nu știu despre structura listei tale. Ele acționează ca contoare.
A pentru / în
bucla și a pentru / de
buclă sunt concepute pentru a itera peste structuri specifice de date. Iterând peste o structură de date înseamnă că treceți prin fiecare dintre elementele sale. A pentru / în
buclă iterează peste cheile dintr-un simplu obiect JavaScript. A pentru / de
buclă iterează peste valorile unui algoritm iterabil. Ce este un proces iterabil? Pur și simplu pus, un iterabil este un obiect care are un iterator. Exemple de iterabilități sunt matrice și seturi. Iteratorul este o proprietate a obiectului care oferă un mecanism pentru traversarea obiectului.
Ceea ce face un iterator special este cum traversează o colecție. Alte bucle trebuie să încarce întreaga colecție în față pentru a putea itera peste ea, în timp ce un iterator trebuie doar să cunoască poziția curentă din colecție.
Accesați elementul curent apelând metoda următoare a iteratorului. Următoarea metodă va returna valoarea elementului curent și a unui boolean pentru a indica momentul când ați atins sfârșitul colecției. Următorul este un exemplu de creare a unui iterator dintr-o matrice.
const alfa = ['a', 'b', 'c']; const = alfa [Simbol.iterator] (); it.next (); // valoare: 'a', done: false it.next (); // valoare: 'b', făcut: false it.next (); // valoare: 'c', făcut: false it.next (); // valoare: undefined, done: true
Puteți, de asemenea, să repetați valorile iteratorului folosind a pentru / de
buclă. Utilizați această metodă când știți că doriți să accesați toate obiectele din obiect. Acesta este modul în care ați folosi o buclă pentru a trece prin lista precedentă:
pentru (const elem de ea) console.log (elem);
De ce ai folosi un iterator? Utilizarea unui iterator este benefică atunci când costul calculat al procesării unei liste este ridicat. Dacă aveți o sursă de date care este foarte mare, aceasta poate provoca probleme în programul dvs. dacă încercați să o repetați pentru că întreaga colecție trebuie încărcată.
Cu un iterator, puteți încărca datele în bucăți. Acest lucru este mai eficient deoarece manipulați doar partea din listă de care aveți nevoie, fără a suporta costul suplimentar al procesării întregii liste.
Un exemplu ar putea fi faptul că ați încărcat date dintr-un fișier sau dintr-o bază de date și doriți să afișați progresiv informațiile de pe ecran. S-ar putea să creați un iterator din date și să configurați un handler de evenimente pentru a apuca câteva elemente de fiecare dată când apare evenimentul. Acesta este un exemplu despre cum poate arăta o astfel de implementare:
hai posturile = încărcați (url); lăsați-o = posturi [Symbol.iterator] (); funcția loadPosts (iterabilă, număr) pentru (let i = 0; i < count; i++) display(iterable.next().value); document.getElementById('btnNext').onclick = loadPosts(it, 5);
Dacă doriți să construiți o colecție, puteți face acest lucru cu un generator. O funcție generator poate reveni la valori una câte una, prin întreruperea execuției la fiecare iterație. Când creați o instanță a unui generator, aceste elemente pot fi accesate utilizând un iterator. Aceasta este sintaxa generală pentru crearea unei funcții a generatorului:
function * genFunc () ... valoarea randamentului;
*
înseamnă că aceasta este o funcție a generatorului. Randament
cuvântul cheie întrerupe funcția noastră și furnizează starea generatorului în momentul respectiv. De ce ai folosi un generator? Ați folosi un generator atunci când doriți să obțineți în mod algoritmic o valoare într-o colecție. Este deosebit de util dacă aveți o colecție foarte mare sau infinită. Să examinăm un exemplu pentru a înțelege cum ne ajută acest lucru.
Să presupunem că aveți un joc de piscină online pe care l-ați construit și doriți să potriviți jucătorii cu camerele de jocuri. Obiectivul dvs. este de a genera toate modurile în care puteți alege doi jucători distinși din lista dvs. de 2 000 de jucători. Combinațiile cu doi jucători generate de listă ['a', 'b', 'c', 'd']
va fi ab, ac, ad, bc, bd, cd
. Aceasta este o soluție folosind bucle imbricate:
combinații de funcții (listă) const n = list.length; permite rezultatul = []; pentru (let i = 0; i < n - 1; i++) for (let j = i + 1; j < n; j++) result.push([list[i], list[j]]); return result; console.log(combos(['a', 'b', 'c', 'd']));
Acum încercați să executați funcția cu o listă de 2.000 de elemente. (Puteți inițializa lista folosind o buclă pentru care adaugă numerele de la 1 la 2000 la o matrice). Ce se întâmplă acum când executați codul?
Când rulez codul într-un editor online, pagina web se blochează. Când o încerc în consola Chrome, pot vedea ieșirea încet prin imprimare. Cu toate acestea, procesorul computerului meu începe să meargă în overdrive, și trebuie să forțez să renunț la Chrome. Acesta este codul revizuit care utilizează o funcție a generatorului:
funcția * combo-uri (listă) const n = list.length; pentru (let i = 0; i < n - 1; i++) for (let j = i + 1; j < n; j++) yield [list[i], list[j]]; let it = combos(['a', 'b', 'c', 'd']); it.next();
Un alt exemplu este dacă vrem să generăm numerele din secvența Fibonacci până la infinit. Iată o implementare:
funcția * fibGen () lasă curent = 0; următoarea = 1; în timp ce (adevărat) randament curent; let nextNum = curent + următor; curent = următor; next = nextNum; lasa = fibGen (); . It.next () valoare; // 0 ea.next () valoare; // 1 este.next () valoare; // 1 este.next () valoare; // 2
În mod normal, o buclă infinită vă va prăbuși programul. fibGen
funcția este capabilă să funcționeze pentru totdeauna, deoarece nu există o condiție de oprire. Dar, deoarece este un generator, controlați când fiecare pas este executat.
Iteratoarele și generatoarele vin la îndemână când doriți să procesați o colecție incremental. Câștigați eficiență prin urmărirea stării colecției în locul tuturor articolelor din colecție. Elementele din colecție sunt evaluate unul câte unul, iar evaluarea restului colecției este întârziată până târziu.
Iteratoarele oferă o modalitate eficientă de a traversa și manipula liste mari. Generatoarele oferă o modalitate eficientă de a crea liste. Ar trebui să încercați aceste tehnici atunci când altfel veți folosi un algoritm complex sau veți implementa programe paralele pentru a vă optimiza codul.
Dacă sunteți în căutarea unor resurse suplimentare pentru a studia sau a utiliza în munca dvs., verificați ce avem disponibil în piața Envato.
Am creat un ghid complet care vă ajută să învățați JavaScript, indiferent dacă începeți doar ca dezvoltator web sau doriți să explorați subiecte mai avansate.