(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': data().getTime(),įvykis:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-5LHNRP9'); Keletas gudrybių, kaip pagreitinti JavaScript programą - The Codest
The Codest
  • Apie mus
  • Paslaugos
    • Programinės įrangos kūrimas
      • Priekinės dalies kūrimas
      • Galinės dalies kūrimas
    • Staff Augmentation
      • Priekinės dalies kūrėjai
      • Atgalinės versijos kūrėjai
      • Duomenų inžinieriai
      • Debesų inžinieriai
      • QA inžinieriai
      • Kita
    • Patariamoji tarnyba
      • Auditas ir konsultacijos
  • Pramonės šakos
    • Fintech ir bankininkystė
    • E-commerce
    • Adtech
    • Sveikatos technologijos
    • Gamyba
    • Logistika
    • Automobiliai
    • IOT
  • Vertė už
    • CEO
    • CTO
    • Pristatymo vadybininkas
  • Mūsų komanda
  • Case Studies
  • Sužinokite, kaip
    • Tinklaraštis
    • Susitikimai
    • Interneto seminarai
    • Ištekliai
Karjera Susisiekite su mumis
  • Apie mus
  • Paslaugos
    • Programinės įrangos kūrimas
      • Priekinės dalies kūrimas
      • Galinės dalies kūrimas
    • Staff Augmentation
      • Priekinės dalies kūrėjai
      • Atgalinės versijos kūrėjai
      • Duomenų inžinieriai
      • Debesų inžinieriai
      • QA inžinieriai
      • Kita
    • Patariamoji tarnyba
      • Auditas ir konsultacijos
  • Vertė už
    • CEO
    • CTO
    • Pristatymo vadybininkas
  • Mūsų komanda
  • Case Studies
  • Sužinokite, kaip
    • Tinklaraštis
    • Susitikimai
    • Interneto seminarai
    • Ištekliai
Karjera Susisiekite su mumis
Atgal rodyklė GRĮŽTI ATGAL
2019-10-08
Programinės įrangos kūrimas

Keletas gudrybių, kaip pagreitinti JavaScript programą

The Codest

Bartosz Slysz

Software Engineer

Tobulėjant naršyklių technologijoms, žiniatinklio programose vis daugiau logikos pradėta perkelti į priekinę dalį, taip palengvinant serverio darbą ir sumažinant operacijų, kurias jis turi atlikti, skaičių. Pagrindinėse CRUD programose serverio vaidmuo apsiriboja autorizavimu, patvirtinimu, ryšiu su duomenų bazėmis ir reikiama verslo logika. Likusią duomenų logikos dalį, kaip paaiškėja, lengvai gali atlikti kodas, atsakingas už programos atvaizdavimą vartotojo sąsajos pusėje.

Šiame straipsnyje pabandysiu jums parodyti keletą pavyzdžių ir modelių, kurie padės išlaikyti mūsų kodas efektyviai, tvarkingai ir greitai.

Prieš gilindamasis į konkrečius pavyzdžius - šiame straipsnyje norėčiau sutelkti dėmesį tik į atvejus, kurie, mano nuomone, gali netikėtai paveikti programos greitį. Tačiau tai nereiškia, kad visais įmanomais atvejais greitesnių sprendimų naudojimas yra geriausias pasirinkimas. Toliau pateiktus patarimus veikiau reikėtų vertinti kaip tai, į ką turėtumėte atkreipti dėmesį, kai mūsų programa veikia lėtai, pavyzdžiui, produktuose, kuriuose reikia žaidimų atvaizdavimo arba sudėtingesnių grafikų drobėje, vaizdo operacijų arba veiklos, kurią norime kuo greičiau sinchronizuoti realiuoju laiku.

Pirmiausia - Array.prototype metodai

Didelę dalį taikomosios logikos grindžiame masyvais - jų atvaizdavimu, rūšiavimu, filtravimu, elementų sumavimu ir pan. Lengvai, skaidriai ir natūraliai naudojame jų integruotus metodus, kurie tiesiog leidžia mus atlikti įvairius skaičiavimus, grupavimą ir pan. Kiekvienu atveju jie veikia panašiai - kaip argumentą perduodame funkciją, kurioje daugeliu atvejų per kiekvieną iteraciją paeiliui stumiama elemento reikšmė, indeksas ir masyvas. Nurodyta funkcija atliekama kiekvienam masyvo elementui, o rezultatas interpretuojamas skirtingai, priklausomai nuo metodo. Plačiau neaptarinėsiu Array.prototype metodų, nes noriu sutelkti dėmesį į tai, kodėl daugeliu atvejų jis veikia lėtai.

Masyvo metodai yra lėti, nes jie atlieka funkciją kiekvienam elementui. Variklio požiūriu iškviesta funkcija turi paruošti naują iškvietimą, suteikti atitinkamą sritį ir daugybę kitų priklausomybių, todėl šis procesas yra daug ilgesnis nei konkretaus kodo bloko pakartojimas konkrečioje srityje. Ir tai tikriausiai yra pakankamos pagrindinės žinios, kad galėtume suprasti toliau pateiktą pavyzdį:

(() => {
const randomArray = [...Array(1E6).keys()].map(() => ({ value: Math.random() }));

console.time('Suma pagal sumažinti');
const reduceSum = randomArray
    .map(({ value }) => value)
    .reduce((a, b) => a + b);
console.timeEnd('Suma pagal reduce');

console.time('Suma pagal for ciklą');
leiskite forSum = randomArray[0].value;
for (let index = 1; index < randomArray.length; index++) {
    forSum += randomArray[index].value;
}
console.timeEnd('Suma pagal for ciklą');

console.log(reduceSum === forSum);

})();

Žinau, kad šis testas nėra toks patikimas kaip lyginamieji standartai (prie jų grįšime vėliau), tačiau jis įjungia įspėjamąją lemputę. Atsitiktiniu atveju mano kompiuteryje paaiškėjo, kad kodas su for ciklu gali būti maždaug 50 kartų greitesnis, jei palyginsime jį su elementų atvaizdavimu, o tada sumažinimu, kuriais pasiekiamas tas pats efektas! Kalbama apie veikimą su tam tikru keistu objektu, sukurtu tik tam, kad būtų pasiektas konkretus skaičiavimų tikslas. Taigi, sukurkime ką nors legalesnio, kad būtų galima objektyviai vertinti masyvų metodus:

(() => {
const randomArray = [...Array(1E6).keys()].map(() => ({ value: Math.random() }));

console.time('Suma pagal sumažinti');
const reduceSum = randomArray
    .reduce((a, b) => ({ vertė: a.value + b.value })).value
console.timeEnd('Suma pagal reduce');

console.time('Suma pagal for ciklą');
leiskite forSum = randomArray[0].value;
for (let index = 1; index < randomArray.length; index++) {
    forSum += randomArray[index].value;
}
console.timeEnd('Suma pagal for ciklą');

console.log(reduceSum === forSum);

})();

Žinau, kad šis testas nėra toks patikimas kaip lyginamieji standartai (prie jų grįšime vėliau), tačiau jis įjungia įspėjamąją lemputę. Atsitiktiniu atveju mano kompiuteryje paaiškėjo, kad kodas su for ciklu gali būti maždaug 50 kartų greitesnis, jei palyginsime jį su elementų atvaizdavimu, o tada sumažinimu, kuriais pasiekiamas tas pats efektas! Taip yra todėl, kad šiuo konkrečiu atveju sumai gauti naudojant redukavimo metodą reikia atvaizduoti masyvą grynoms reikšmėms, kurias norime apibendrinti. Taigi, sukurkime ką nors įteisinamesnio, kad būtų objektyviau apie masyvų metodus:

(() => {
const randomArray = [...Array(1E6).keys()].map(() => ({ value: Math.random() }));

console.time('Suma pagal sumažinti');
const reduceSum = randomArray
    .reduce((a, b) => ({ vertė: a.value + b.value })).value
console.timeEnd('Suma pagal reduce');

console.time('Suma pagal for ciklą');
leiskite forSum = randomArray[0].value;
for (let index = 1; index < randomArray.length; index++) {
    forSum += randomArray[index].value;
}
console.timeEnd('Suma pagal for ciklą');

console.log(reduceSum === forSum);

})();

Pasirodo, mūsų 50 kartų padidinimas sumažėjo iki 4 kartų. Atsiprašome, jei jaučiatės nusivylę! Kad išliktume objektyvūs iki galo, dar kartą išanalizuokime abu kodus. Pirmiausia - nekaltai atrodantys skirtumai padvigubino mūsų teorinio skaičiavimo sudėtingumo sumažėjimą; užuot iš pradžių atvaizdavę, o paskui sudėję grynus elementus, mes vis dar operuojame objektais ir konkrečiu lauku, kad galiausiai ištrauktume ir gautume mus dominančią sumą. Problema iškyla, kai į kodą pažvelgia kitas programuotojas - tada, palyginti su anksčiau parodytais kodais, pastarasis tam tikru momentu praranda abstraktumą.

Taip yra todėl, kad nuo antrosios operacijos, kad mes veikiame ant svetimo objekto, su domina mus laukas ir antrasis, standartinis objektas iteruoto masyvo. Nežinau, ką apie tai manote jūs, bet, mano požiūriu, antrajame kodo pavyzdyje for ciklo logika yra daug aiškesnė ir tikslingesnė nei šis keistai atrodantis reduktorius. Ir vis dėlto, nors tai nebėra mitinis 50, vis tiek 4 kartus greičiau, kalbant apie skaičiavimo laiką! Kadangi kiekviena milisekundė yra vertinga, pasirinkimas šiuo atveju paprastas.

Labiausiai stebinantis pavyzdys

Antrasis dalykas, kurį norėjau palyginti, yra susijęs su Math.max metodu arba, tiksliau, su milijono elementų įdėjimu ir didžiausių bei mažiausių elementų išskyrimu. Paruošiau kodą, laiko matavimo metodus taip pat, tada paleidžiu kodą ir gaunu labai keistą klaidą - viršijamas kamino dydis. Štai kodas:

(() => {
const randomValues = [...Array(1E6).keys()].map(() => Math.round(Math.random() * 1E6) - 5E5);

console.time('Math.max su ES6 plitimo operatoriumi');
const maxBySpread = Math.max(...randomValues);
console.timeEnd('Math.max su ES6 sklaidos operatoriumi');

console.time('Math.max su for ciklu');
leiskite maxByFor = randomValues[0];
for (let index = 1; index  maxByFor) {
        maxByFor = randomValues[index];
    }
}
console.timeEnd('Math.max su for ciklu');

console.log(maxByFor === maxBySpread);

})();
(() => {
const randomValues = [...Array(1E6).keys()].map(() => Math.round(Math.random() * 1E6) - 5E5);

console.time('Math.max su ES6 plitimo operatoriumi');
const maxBySpread = Math.max(...randomValues);
console.timeEnd('Math.max su ES6 sklaidos operatoriumi');

console.time('Math.max su for ciklu');
leiskite maxByFor = randomValues[0];
for (let index = 1; index  maxByFor) {
        maxByFor = randomValues[index];
    }
}
console.timeEnd('Math.max su for ciklu');

console.log(maxByFor === maxBySpread);

})();

Pasirodo, kad vietiniai metodai naudoja rekursiją, kurią v8 versijoje riboja iškvietimų kaminai, o jų skaičius priklauso nuo aplinkos. Tai mane labai nustebino, bet iš to peršasi išvada: gimtasis metodas yra greitesnis, jei mūsų masyvas neviršija tam tikro magiško elementų skaičiaus, kuris mano atveju pasirodė esąs 125375. Esant tokiam elementų skaičiui, rezultatas for buvo 5 kartus greitesnis, jei lygintume su ciklu. Tačiau virš minėto elementų skaičiaus ciklas for neabejotinai laimi - priešingai nei priešininkas, jis leidžia mums gauti teisingus rezultatus.

Rekursija

Šioje pastraipoje noriu paminėti rekursijos sąvoką. Ankstesniame pavyzdyje ją matėme metodo Math.max ir argumentų sulankstyme, kur paaiškėjo, kad dėl kamino dydžio apribojimo neįmanoma gauti rezultato rekursyviniams iškvietimams, viršijantiems tam tikrą skaičių.

Dabar pamatysime, kaip rekursija atrodo kodo, parašyto JS, o ne su integruotais metodais.Bene klasikinis dalykas, kurį galime parodyti, yra Fibonačio sekos n-ojo nario radimas. Taigi, parašykime tai!

(() => {
const fiboIterative = (n) => {
tegul [a, b] = [0, 1];

    for (let i = 0; i  {
    if(n < 2) {
        return n;
    }

    return fiboRecursive(n - 2) + fiboRecursive(n - 1);
};

console.time('Fibonačio seka pagal for ciklą');
const resultIterative = fiboIterative(30);
console.timeEnd('Fibonačio seka pagal for ciklą');

console.time('Fibonačio seka pagal rekursiją');
const resultRecursive = fiboRecursive(30);
console.timeEnd('Fibonačio seka pagal rekursiją');

console.log(resultRecursive === resultIterative);

})();

Šiuo konkrečiu atveju, kai mano kompiuteryje apskaičiuojamas 30-asis sekos elementas, taikant iteracinį algoritmą rezultatą gauname per maždaug 200 kartų trumpesnį laiką.

Tačiau rekursyviniame algoritme galima ištaisyti vieną dalyką - pasirodo, jis veikia daug efektyviau, kai naudojame taktiką, vadinamą uodegos rekursija. Tai reiškia, kad ankstesnės iteracijos metu gautą rezultatą perduodame kaip argumentus gilesniems iškvietimams. Tai leidžia sumažinti reikiamų iškvietimų skaičių ir dėl to pagreitina rezultato gavimą. Atitinkamai pataisykime savo kodą!

(() => {
const fiboIterative = (n) => {
tegul [a, b] = [0, 1];

    for (let i = 0; i  {
    if(n === 0) {
        return first;
    }

    return fiboTailRecursive(n - 1, second, first + second);
};

console.time('Fibonačio seka pagal for ciklą');
const resultIterative = fiboIterative(30);
console.timeEnd('Fibonačio seka pagal for ciklą');

console.time('Fibonačio seka pagal uodegos rekursiją');
const resultRecursive = fiboTailRecursive(30);
console.timeEnd('Fibonačio seka pagal uodegos rekursiją');

console.log(resultRecursive === resultIterative);

})();

Čia nutiko tai, ko nesitikėjau - kai kuriais atvejais uodegos rekursijos algoritmo rezultatas (apskaičiuojant 30-ąjį sekos elementą) buvo beveik dvigubai greitesnis nei iteracinis algoritmas. Nesu visiškai tikras, ar taip nutiko dėl to, kad v8 optimizavo uodegos rekursiją, ar dėl to, kad for ciklas nebuvo optimizuotas šiam konkrečiam iteracijų skaičiui, tačiau rezultatas vienareikšmis - uodegos rekursija laimi.

Tai keista, nes iš esmės for ciklas daug mažiau abstrahuoja žemesnio lygmens skaičiavimo veiksmus ir, galima sakyti, yra artimesnis pagrindiniam kompiuterio veikimui. Vis dėlto rezultatai neginčijami - gudriai suprojektuota rekursija pasirodo esanti greitesnė už iteraciją.

Kuo dažniau naudokite asinchroninius iškvietimo sakinius

Paskutinę pastraipą norėčiau skirti trumpam priminimui apie operacijų atlikimo būdą, kuris taip pat gali turėti didelės įtakos mūsų programos greičiui. Kaip turėtumėte žinoti, JavaScript yra vienos gijos kalba, kurioje visos operacijos atliekamos naudojant įvykių ciklo mechanizmą. Viskas susiję su ciklu, kuris vyksta vis iš naujo ir iš naujo, o visi šio ciklo veiksmai yra susiję su specialiais nurodytais veiksmais.

Kad ši kilpa būtų greita ir visi ciklai mažiau lauktų savo eilės, visi elementai turėtų būti kuo greitesni. Venkite vykdyti ilgas operacijas pagrindiniame sraute - jei kas nors užtrunka per ilgai, pabandykite šiuos skaičiavimus perkelti į "WebWorker" arba padalyti į asinchroniškai vykdomas dalis. Tai gali sulėtinti kai kurias operacijas, tačiau padidinti visos JS ekosistemos, įskaitant IO operacijas, pavyzdžiui, pelės judėjimo ar laukiančios HTTP užklausos tvarkymą, našumą.

Santrauka

Apibendrinant, kaip minėta anksčiau, tam tikrais atvejais gali pasirodyti, kad lenktyniavimas dėl milisekundžių, kurias galima sutaupyti pasirenkant algoritmą, yra beprasmis. Kita vertus, tokių dalykų nepaisymas programose, kuriose reikia sklandaus veikimo ir greitų rezultatų, gali būti pražūtingas jūsų programai. Kai kuriais atvejais, be algoritmo greičio, reikėtų užduoti dar vieną papildomą klausimą - ar abstrakcija veikia tinkamu lygmeniu? Ar programuotojas, skaitantis kodą, galės jį suprasti be problemų?

Vienintelis būdas - užtikrinti pusiausvyrą tarp našumo, įgyvendinimo paprastumo ir tinkamos abstrakcijos bei būti tikriems, kad algoritmas teisingai veikia ir mažų, ir didelių kiekių atveju. duomenys. Tai padaryti gana paprasta - būkite protingi, projektuodami algoritmą atsižvelkite į skirtingus atvejus ir pasirūpinkite, kad jis kuo efektyviau veiktų vidutinio vykdymo metu. Be to, patartina suprojektuoti testus - įsitikinkite, kad algoritmas grąžina tinkamą informaciją skirtingiems duomenims, kad ir kaip jis veiktų. Pasirūpinkite tinkamomis sąsajomis - kad tiek metodų įvestis, tiek išvestis būtų skaitomos, aiškios ir tiksliai atspindėtų, ką jos daro.

Anksčiau minėjau, kad grįšiu prie algoritmų greičio matavimo patikimumo pirmiau pateiktuose pavyzdžiuose. Matuoti juos naudojant console.time nėra labai patikima, tačiau tai geriausiai atspindi standartinį naudojimo atvejį. Šiaip ar taip, toliau pateikiu lyginamuosius testus - kai kurie iš jų atrodo šiek tiek kitaip nei vienkartinis vykdymas dėl to, kad lyginamieji testai tiesiog kartoja tam tikrą veiklą tam tikru laiku ir ciklams naudoja v8 optimizavimą.

  • https://jsben.ch/KhAqb - sumažinti vs for ciklas
  • https://jsben.ch/F4kLY - optimizuotas mažinimas ir for ciklas
  • https://jsben.ch/MCr6g - Math.max vs for loop
  • https://jsben.ch/A0CJB - rekursinis fibo ir iteracinis fibo
  • https://jsben.ch/NFLsl - uodegos rekursinis fibo vs iteracinis fibo 

Štai ir viskas - mėgaukitės įsilaužimu!

Skaityti daugiau:

Kaip patobulinti Vue.js programas? Keletas praktinių patarimų

Būdai, kaip padidinti "Rails" našumą

Kaip parašyti gerą ir kokybišką kodą?

Susiję straipsniai

Išmaniojo telefono sveikatos priežiūros programėlės su širdies piktograma ir kylančia sveikatos diagrama, pažymėtos The Codest logotipu, iliustracija, vaizduojanti skaitmeninės sveikatos ir sveikatos technologijų sprendimus.
Programinės įrangos kūrimas

Sveikatos priežiūros programinė įranga: Sveikatos priežiūros paslaugos: tipai, naudojimo atvejai

Įrankiai, kuriais šiandien naudojasi sveikatos priežiūros organizacijos, nė iš tolo neprimena prieš kelis dešimtmečius naudotų popierinių kortelių. sveikatos priežiūros programinė įranga dabar padeda sveikatos sistemoms, pacientų priežiūrai ir šiuolaikiniam sveikatos priežiūros paslaugų teikimui klinikinėse ir...

GERIAUSIAS
Abstrakti mažėjančios stulpelinės diagramos su kylančia rodykle ir auksine moneta, simbolizuojančia ekonomiškumą arba taupymą, iliustracija. Viršutiniame kairiajame viršutiniame kampe pavaizduotas The Codest logotipas ir šūkis "In Code We Trust" šviesiai pilkame fone.
Programinės įrangos kūrimas

Kaip padidinti savo Dev komandą neprarandant produkto kokybės

Didinate savo kūrėjų komandą? Sužinokite, kaip augti neprarandant produkto kokybės. Šiame vadove aptariami ženklai, kad atėjo laikas didinti komandą, komandos struktūra, įdarbinimas, vadovavimas ir įrankiai - ir kaip The Codest gali...

GERIAUSIAS
Programinės įrangos kūrimas

Sukurkite ateičiai atsparias žiniatinklio programas: The Codest ekspertų komandos įžvalgos

Sužinokite, kaip The Codest puikiai kuria keičiamo dydžio interaktyvias žiniatinklio programas, naudodama pažangiausias technologijas ir užtikrindama vientisą naudotojų patirtį visose platformose. Sužinokite, kaip mūsų patirtis skatina skaitmeninę transformaciją ir verslo...

GERIAUSIAS
Programinės įrangos kūrimas

10 geriausių Latvijoje įsikūrusių programinės įrangos kūrimo įmonių

Naujausiame mūsų straipsnyje sužinokite apie geriausias Latvijos programinės įrangos kūrimo įmones ir jų inovatyvius sprendimus. Sužinokite, kaip šie technologijų lyderiai gali padėti pakelti jūsų verslo lygį.

thecodest
Įmonių ir didinimo sprendimai

"Java" programinės įrangos kūrimo pagrindai: A Guide to outsourcing Outsourcing Successfully

Išnagrinėkite šį esminį vadovą, kaip sėkmingai outsourcing "Java" programinę įrangą kurti, kad padidintumėte efektyvumą, įgytumėte patirties ir sėkmingai įgyvendintumėte projektus su The Codest.

thecodest

Prenumeruokite mūsų žinių bazę ir būkite nuolat informuoti apie IT sektoriaus patirtį.

    Apie mus

    The Codest - tarptautinė programinės įrangos kūrimo bendrovė, turinti technologijų centrus Lenkijoje.

    Jungtinė Karalystė - būstinė

    • 303B biuras, 182-184 High Street North E6 2JA
      Londonas, Anglija

    Lenkija - vietiniai technologijų centrai

    • Fabryczna biurų parkas, Aleja
      Pokoju 18, 31-564 Krokuva
    • Brain Embassy, Konstruktorska
      11, 02-673 Varšuva, Lenkija

    The Codest

    • Pagrindinis
    • Apie mus
    • Paslaugos
    • Case Studies
    • Sužinokite, kaip
    • Karjera
    • Žodynas

    Paslaugos

    • Patariamoji tarnyba
    • Programinės įrangos kūrimas
    • Galinės dalies kūrimas
    • Priekinės dalies kūrimas
    • Staff Augmentation
    • Atgalinės versijos kūrėjai
    • Debesų inžinieriai
    • Duomenų inžinieriai
    • Kita
    • QA inžinieriai

    Ištekliai

    • Faktai ir mitai apie bendradarbiavimą su išoriniu programinės įrangos kūrimo partneriu
    • Iš JAV į Europą: Kodėl Amerikos startuoliai nusprendžia persikelti į Europą?
    • Technikos plėtros centrų užsienyje palyginimas: Tech Offshore Europa (Lenkija), ASEAN (Filipinai), Eurazija (Turkija)
    • Kokie yra svarbiausi CTO ir CIO iššūkiai?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Autorinės teisės © 2026 The Codest. Visos teisės saugomos.

    lt_LTLithuanian
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian es_ESSpanish nl_NLDutch etEstonian elGreek pt_PTPortuguese cs_CZCzech lvLatvian is_ISIcelandic lt_LTLithuanian