Încărcarea asincronă a scripturilor. Creăm un proiect de testare. Suport și motoare de browser moderne

Uneori este nevoie de încărcarea asincronă a datelor pas cu pas. Și ar putea fi orice. Pornind de la încărcarea directoarelor dependente (de exemplu, țară -> orașe), terminând cu combinarea și procesarea informațiilor cu diverse surse(de exemplu, utilizați mai multe servicii diferite, iar fiecare dintre ei cheltuie timpuri diferite pentru generarea datelor).

Și acum puțin mai simplu.

Probleme cu încărcarea pas cu pas a datelor asincrone în jQuery (ajax)

Dacă trebuie să conectați mai multe solicitări ajax executate secvențial în jQuery, atunci cel mai mult solutie simpla will - face un apel la următoarea funcție la sfârșitul fiecărui handler de succes. Acest lucru nu este doar destul de simplu, dar nici nu provoacă probleme. De exemplu,

// Prima solicitare $.ajax(url, ( ... succes: function (rezultat) ( // Un cod... // Apelarea urmatorului handler nextLoader(); ) ));

Și acum, să spunem, în fața ta stă puțin mai mult sarcină dificilă. De exemplu, trebuie să rulați o funcție numai după ce au fost finalizate mai multe solicitări asincrone (de exemplu, obținerea de bule pentru un site). Desigur, ele pot fi conectate și într-un lanț drept, așa cum se arată mai sus. Dar, în același timp, însăși esența asincroniei începe să se piardă. Și se poate dovedi, de asemenea, că construiți o dependență între blocuri complet nelegate. Sunteți de acord că indicatorul TCI și datele whois nu depind în totalitate unul de celălalt.

Cu toate acestea, în ciuda tuturor subtilităților, o astfel de problemă poate fi rezolvată destul de repede, deși puțin stângaci.

Dar ce vei face dacă sarcina ta se va dovedi a fi și mai dificilă? Când trebuie să distribuiți toate operațiunile și încărcarea datelor în etape. De exemplu, creați un șablon de dialog. Prima etapă va implica obținerea de date pentru toate câmpurile (liste derulante, grupuri de casete de selectare etc.). În a doua etapă, vor fi definiți handlere pentru câmpurile create. Și la a treia etapă, după sarcina completa„orice și totul”, acces deschis la diverse butoaneși alte elemente de interfață (pentru ca mâinile jucăușe să nu creeze multe probleme pentru tine). Pur vizual ar putea arăta astfel:

Sunteți de acord că organizarea apelurilor tuturor funcțiilor dintr-un singur lanț nu este doar o sarcină ușoară, ci și nici foarte plăcută. În plus, imaginați-vă că trebuie să adăugați mai multe câmpuri și diferiți handlere. Ce se va întâmpla? Capul tău va începe să fiarbă de la căutarea locurilor potrivite „unde să introduci”. Aici aveți deja nevoie de un fel de mecanism care vă va permite să aranjați toate lansările în etape.

Scriem un script pentru a organiza pas cu pas încărcarea asincronă în jQuery

Primul pas este să decideți cu privire la întrebarea complet logică „de ce să nu folosiți biblioteci gata făcute?” Ca atare, nu există niciun răspuns la această întrebare. Totul depinde foarte mult de sarcină. Deoarece cuvântul „bibliotecă” înseamnă de obicei:

  • lipsa controlabilității codului (nu puteți schimba logica internă a bibliotecii; și dacă faceți acest lucru, atunci orice modificare poate reveni să vă bântuie în viitor)
  • nevoia de a o studia proprietăți de bazăși principii (de obicei, aceasta se rezumă la citirea tuturor documentației posibile și a o grămadă de teste diferite)
  • restrictii asupra versiuni jQuery(dacă sunt utilizate mecanisme complexe ale nucleului, atunci este posibil să faceți legătura la versiunea bibliotecilor jQuery)
  • posibile probleme de compatibilitate cu alte scripturi (este departe de a fi sigur că biblioteca se va comporta corect cu alte biblioteci)
  • bogăția excesivă a funcționalității și, ca urmare, prezența „restricțiilor suplimentare”
  • etc.

Notă: Nu vă lăsați induși în eroare, deoarece bibliotecile au cantitate uriașă pro. Dacă vă amintiți, jQuery este aceeași bibliotecă. Articolul se concentrează pe riscurile și investițiile suplimentare de timp care vi se pot cere.

De aceea trebuie mai întâi să vă decideți sarcinile (numărul, frecvența de apariție), timpul (cât sunteți dispus să cheltuiți pentru rezolvarea problemei), ce sunteți dispus să sacrifici (este capacitatea de a corecta rapid ceva important pentru tine). ; este importantă dimensiunea bibliotecilor, cât de mult vi se potrivește, preferințe (de exemplu, nu folosiți biblioteci). Și numai după ce răspundeți la aceste întrebări, încercați să răspundeți la întrebarea „de ce merită sau nu să folosiți biblioteci gata făcute?”

Dacă ți-ai răspuns singur că vrei să folosești biblioteci, atunci, opțional, poți descărca un caz de testare gata făcut cu un script gata făcut la sfârșitul articolului.

Dacă sunteți plin de entuziasm și determinare, atunci vom trece la acțiuni ulterioare.

Compilarea cerințelor pentru script

Înainte de a implementa orice, este necesar să se elaboreze cerințe mici pentru a nu fi deturnat în timpul implementării. Rezultă o listă ca aceasta:

  • Conectarea și configurarea scriptului ar trebui să aibă loc automat (trebuie doar să conectați fișierul js)
  • Reconectarea fișierului script nu ar trebui să provoace o blocare
  • Utilizați numai mecanisme jQuery standard
  • Interfața ar trebui să fie simplă și ușor de înțeles
  • Puteți crea mai multe lanțuri independente de etape
  • Ar trebui să puteți întotdeauna să ajustați rapid acțiunile scriptului
  • Scriptul nu ar trebui să impună restricții complexe asupra codului dvs. (maximum - necesitatea de a adăuga o funcție de notificare despre execuția acestuia)

Notă: Formulați întotdeauna cerințe, astfel încât în ​​timpul implementării să nu începeți să faceți ceva care nu este deloc necesar. Și asigurați-vă că includeți puncte „atât de clare”, astfel încât aceste puncte să rămână „atât de clare”.

Realizarea unui proiect de testare

Structura proiectului va arăta astfel:

  • css - director cu stiluri
    • template.css - testarea stilurilor de proiect
  • imagini - catalog cu imagini (pentru efect vizual)
    • ajax-loader.gif - se încarcă imaginea
  • js - director cu scripturi
    • jquery-ajax-stage.js - script pentru încărcare în etape
  • data.json - date de testare
  • index.html - pagina de start

Notă: Când creați structura proiectului de testare, încercați să o aduceți cât mai aproape de structura proiectului real. Acest lucru vă va ajuta să identificați problemele legate de structură în timpul dezvoltării.

Fișier cu date de testare - data.json

Acest fișier este necesar doar pentru a vă asigura că încărcarea datelor prin ajax nu va afecta nimic. Îl puteți completa cu orice json. De exemplu, așa:

( date: „O mulțime de date”)

Notă: Încercați să faceți cazurile de testare cât mai asemănătoare cu cele reale. Chiar dacă apelurile de funcție sunt lipsite de sens.

Fișier de stil - template.css

Acest fișier este necesar doar pentru a afișa toate stilurile separat. Deoarece stilurile nu au nimic de-a face cu dezvoltarea scenariului în sine. Da, și este considerat doar o bună practică. Stilurile în sine:

Left-table (float: stânga; padding-right: 10px; ) .right-table (float: left; padding-right: 10px; ) table.table-loader (border-spacing: 0px; border-collapse: collapse; width : 300px; ) table.table-loader tr (padding: 5px; chenar: 1px solid #ccc; )

Fișier script pentru încărcarea asincronă în etape - jquery-ajax-stage.js

Implementarea în sine a încărcării asincrone pas cu pas.

(funcție (parentObject) ( // Protecție împotriva redefinirii if(parentObject.eventManager) return; // Definiți obiectul parentObject.eventManager = ( // Adăugați o etapă addStage: function (el, stageName) ( var elCount = $( el). lungime // Verificați corectitudinea parametrilor if(elCount > 0 && !!stageName) ( // O astfel de etapă există deja dacă (($(el).get(0).eventStages = $(el))); .get(0).eventStages || ())) returnează // Definiți „nfg $(el).get(0).eventStages = ( waiterCount: 0, // Contor de obiecte în așteptare pentru date onEvent: // în; această matrice toate funcțiile care vor fi apelate vor fi stocate);

) ), // Eliminați etapa removeStage: function (el, stageName) ( var elCount = $(el).length; // Verificați corectitudinea parametrilor if(elCount > 0 && !!stageName) ( // Un astfel de etapa este găsită dacă (( $(el).get(0).eventStages = $(el).get(0).eventStages || ())) ( șterge ($(el).get(0).eventStages = $(el).get (0).eventStages || ()); ($(el).get(0).eventStages = $(el).get(0).eventStages || ()) = null ) ) ), // Mărește contorul de funcții executate pentru etapa addStageWaiter: function (el, stageName) ( var elCount = $(el).length, stage = ($(el).get(0).eventStages = $(el)) .get(0).eventStages || () // Verificați corectitudinea parametrilor if(elCount > 0 && !!stageName && stage) ( // Mărește contorul de încărcare stage.waiterCount++; ) ), // Diminuează. contorul de functii executate pentru etapa // I.e. anunță că funcția a fost executată removeStageWaiter: function (el, stageName) ( var elCount = $(el).length, stage = ($(el).get(0).eventStages = $(el).get(0)) .eventStages || () // Verificați corectitudinea parametrilor if(elCount > 0 && !!stageName && stage) ( // Reduceți contorul de încărcare stage.waiterCount--; // Verificați starea etapei aceasta. .checkStage(el, stageName) ), // Verificați starea etapei checkStage: function (el, stageName) ( var elCount = $(el).length, stage = ($(el).get(0)) .eventStages = $(el).get(0) .eventStages || () // Verificați corectitudinea parametrilor if(elCount > 0 && !!stageName && stage) ( if (stage.waiterCount 0) ( /. / coadă FIFO - primul intrat, primul ieșit, ca în magazinul de etapă onEvent.shift() () ) ) ), // Adăugați un apel de funcție care va rula atunci când este executată întreaga etapă onLoadStage: function (el,); stageName, funcHandler) ( var elCount = $(el).length, stage = ($ (el).get(0).eventStages = $(el).get(0).eventStages || ()); // Verificați parametrii sunt corecti if(elCount > 0 && !!stageName && stage && typeof (funcHandler) = == „funcție”) ( // Adăugați un handler stage.onEvent.push(funcHandler);

// Verificați starea stadiului this.checkStage(el, stageName); ) ) ); ))(fereastră); Pagina de testare - index.html

Pagina de test s-a dovedit a fi destul de mare (aproximativ 160 de linii), așa că va fi dată doar o parte din cod.

Versiune completă

puteți găsi întotdeauna fișierul în arhiva zip.

Să definim o funcție care va crea funcții de testare pentru etapele:

function getFakeLoader(storage, currStage, startDate, selector) ( return function () ( setTimeout(function ()) ( $.ajax("data.json?callback=?", ( contentType: "text/plain; charset=utf-8) ", dataType: "jsonp", jsonpCallback: function (rezultat) ( $(selector).html("Timp de la început: " + ((+new Date() - startDate)/1000.0).toFixed(2) + " secunde "); // Scrieți timpul de încărcare window.eventManager.removeStageWaiter(storage, currStage); // Scădeți contorul ) )); ), Math.random() * (3000) + 1000 // Întârziere de la 1 la 4 secunde );

Creăm o funcție care va descrie logica pentru fiecare bloc de testare:

function formTestFor(selector) ( $(selector + " .start-process").click(function () ( var startDate = new Date(); // Pentru frumusețe, adăugați imagini setLoaderImgs(selector); // Definiți fereastra etapelor .eventManager .addStage($(selector + " .table-loader"), "1"); window.eventManager.addStage($(selector + " .table-loader"), "2"); ($ (selector + " .table-loader"), "3" // Blocați butonul până la sfârșitul etapei $(selector + " .start-process").attr("dezactivat", "dezactivat"); ); așteptarea a 3 încărcări pe etapă // De fapt, aceste acțiuni ar trebui să apară în locurile în care sunt lansate funcțiile de etapă window.eventManager.addStageWaiter($(selector + " .table-loader"), "1"); $(selector + " .table-loader"), "3"); // Acum să creăm ordine inversă(pentru claritate) funcții de încărcare // De fapt, aceste acțiuni ar trebui să apară în locurile în care funcțiile sunt definite window.eventManager.onLoadStage($(selector + " .table-loader"), "2", getFakeLoader($(selector + " .table-loader"), "3", startDate, selector + " .row-3 .td-1"));
Încărcarea este completă"); )); // După ce a treia etapă este finalizată, deblocați butonul onLoadStage window.eventManager.onLoadStage($(selector + " .table-loader"), "3", funcția () ( // Deblocați butonul $(selector + " .start-process").attr("disabled", null ) // Acum rulați funcțiile din prima etapă getFakeLoader($(selector + " .table-loader"), "1" , startDate, selector + " .row-1 .td-1")(); getFakeLoader($(selector + " .table-loader"), "1", startDate, selector + " .row-1 .td-2 ")(); getFakeLoader($(selector + " .table-loader"), "1", startDate, selector + " .row-1 .td-3")(); // Observați... ));

Acum colectăm toate fișierele în proiect și trecem la testarea și demonstrația inițială.

Să vedem rezultatul

Deschideți fișierul index.html în browser. Ar trebui să fie afișată următoarea interfață:

După cum puteți vedea, avem două butoane disponibile pentru lansarea proceselor paralele. După ce faceți clic pe ele, descărcarea blocurilor corespunzătoare ar trebui să înceapă. Și va arăta cam așa:

După ce ambele procese și-au încheiat execuția, priviți momentul și asigurați-vă că etapele au avut loc în ordinea corectă:

După ce am finalizat testarea inițială, trecem la verificarea cerințelor:

  • Conectarea și configurarea scriptului ar trebui să aibă loc automat (trebuie doar să conectați fișierul js) - Da
  • Reconectarea fișierului script nu ar trebui să provoace o blocare - Da
  • Folosiți numai mecanisme jQuery standard - Da (a fost folosită doar funcționalitatea selectorului)
  • Interfața ar trebui să fie simplă și ușor de înțeles - Da
  • Puteți crea mai multe lanțuri independente de etape - Da
  • Ar trebui să puteți corecta întotdeauna rapid acțiunile scriptului - Da (scriptul este scris destul de simplu; partea principală constă în verificarea datelor de intrare)
  • Scriptul nu ar trebui să impună restricții complexe asupra codului dvs. (maximum - necesitatea de a adăuga o funcție pentru a notifica finalizarea acesteia) - Da (în interiorul funcțiilor getFakeLoader, este numită doar funcția de notificare despre finalizarea sa)

Acum aveți un script simplu și clar care vă va ajuta să organizați rapid execuția pas cu pas a funcțiilor, fie că este vorba de încărcarea datelor sau pur și simplu de efectuarea de operațiuni.

Salutări, prieteni! Știați că încărcarea JavaScript este unul dintre cele mai mari blocaje în performanța site-ului? Astăzi sarcina mea principală este să explic ce este un script și cum afectează acesta viteza și performanța site-ului.

Un browser care încarcă o etichetă de script oprește redarea paginii până când scriptul se încarcă și se execută. Pagina este blocată, iar browserul nu răspunde la acțiunile utilizatorului timp de câteva secunde. Timpul de întârziere depinde de mai mulți factori:

  • configuratii,
  • viteza conexiunii la internet,
  • dimensiunea fișierului și altele...

Din acest motiv, analizatorul de viteză a site-ului web Google PageSpeed ​​​​Insights recomandă eliminarea din partea de sus a paginii Cod JavaScript, blocându-i afișarea. O bună practică este să plasați scripturi în partea de jos a site-ului, de exemplu înainte de eticheta de închidere sau să configurați încărcarea asincronă.

Dacă codul de script afectează afișarea părții superioare a site-ului, nu îl plasați dosar separat, și încorporați direct în HTML.

JS poate modifica conținutul site-ului și chiar poate redirecționa către o adresă URL diferită. În acest caz, conectarea scriptului de la sfârșitul documentului va duce la efectul de „smucire” a paginii, de încărcare noi sau de modificare a elementelor existente în partea de sus.

Aplicarea atributelor async și defer la eticheta de script

Să ne dăm seama ce este munca asincronă și amânată în JavaScript și care este diferența fundamentală între atributele asincrone și defer. Dar mai întâi, să ne uităm la secvența procesării documentelor când conexiune normală eticheta de script.

1 < src = "example.js" >

ÎN exemplu clar Voi folosi următoarele simboluri:

- procesarea paginii
— încărcarea scriptului
- execuția scriptului

Astfel, secvența de procesare are loc conform următoarei scheme:

Analiza codului HTML este întreruptă în timp ce scriptul se încarcă și se execută, după care continuă. Există o întârziere în afișarea paginii web.

defer atribut

Atributul defer permite browserului să înceapă descărcarea fișierelor js în paralel fără a opri procesarea ulterioară a paginii. Ele sunt executate după analiză completă model de obiect document (din documentul englezesc Model de obiect, prescurtat DOM), browserul garantează consistența în funcție de ordinea în care sunt incluse fișierele.

1 < defer src = "example.js" >

atribut asincron

Suportul pentru atributul async a apărut în HTML5, permite browserului să descarce fișiere js în paralel și să le execute imediat după descărcare, fără a aștepta ca restul paginii să fie procesat.

1 < async src = "example.js" >

Diagrama secvenței de procesare:

Aceasta este o descărcare asincronă. Acest atribut este recomandat pentru utilizare în scripturi care nu au un impact semnificativ asupra afișajului documentului. Acestea includ contoare de colectare a statisticilor ( Google Analytics, Yandex Metrica), coduri de rețea de publicitate (Yandex Advertising Network, Google AdSense), butoane rețelele socialeși așa mai departe.

Viteza de încărcare a site-ului este unul dintre factorii de clasare în Google.

Asincron Conexiune JavaScript Reduce timpul de încărcare a paginii datorită absenței întârzierii. Împreună cu aceasta, recomand comprimarea și îmbinarea fișierelor js într-unul singur, de exemplu, folosind fișierul . Utilizatorilor le plac site-urile rapide 😎

HTML este conceput astfel încât pagina web să fie încărcată secvenţial linie cu linie, încărcând pe rând toate elementele incluse în codul html. Și dacă unul dintre ele nu este disponibil (de exemplu, JavaScript de pe un site extern nu este citit), atunci încărcarea ulterioară a site-ului se oprește.

Când JS de necitit este în partea de sus a paginii, este posibil ca vizitatorul să nu vadă nimic.

Prin urmare, atunci când utilizați JavaScript de pe site-uri terțe pe site-ul dvs., de exemplu pentru a afișa reclame, este foarte recomandabil să le încărcați asincron. În acest caz, JS terță parte nu va întârzia încărcarea și afișarea site-ului dvs.

Din păcate, nu toate rețelele de publicitate oferă posibilitatea de a descărca scripturi în mod asincron. Prin urmare, în acest articol vă voi spune cum să schimbați codul de încărcare sincronă în asincron. Dacă proprietarul acestui script nu oferă această opțiune.

Încărcare JS sincronă standard

De obicei, apelarea unui script de pe un server extern arată astfel:

Încărcare asincronă script cum face Google/Adsense

Am primit ideea de la Google/Adsense. Pentru ca scriptul să se încarce asincron de restul codului HTML, trebuie să adăugați asincron la codul de apel.

Și acum, pentru ca codul să se încarce asincron, apelul nostru de script de la serverul extern ar trebui să arate astfel:

După cum puteți vedea, totul este simplu. Adevărat, acest lucru va funcționa numai în browserele care acceptă standardul HTML5. La momentul scrierii acestui articol, există o majoritate absolută de astfel de browsere.

Opțiunea propusă nu este 100% universală. Multe scripturi pur și simplu nu mai funcționează după efectuarea acestor modificări. Conform recenziilor online, această metodă nu funcționează dacă elementul este utilizat în script document.scrie.

Opțiune fiabilă de încărcare asincronă

Dacă prima opțiune sugerată nu funcționează pentru dvs. Atunci profită următoarele recomandări. Aceasta este în esență încărcare leneșă. Deoarece apelul de script real are loc chiar la sfârșit Pagini HTML, adică atunci când tot conținutul necesar al paginii este deja pe ecran.

În locul din pagină în care doriți să afișați rezultatul Funcționează JavaScript trebuie să creați un bloc div gol:

Apoi la sfârșitul paginii înainte de închidere eticheta BODY introduceți scriptul pentru încărcare asincronă:

// JavaScript care trebuie să fie încărcat asincron // mutați-l în poziție reală afișa document.getElementById("script_block_0").appendChild(document.getElementById("script_ad_0"));

// arată document.getElementById("script_ad_0").style.display = "blocare";

Dacă există mai multe blocuri de publicitate, atunci pentru fiecare dintre ele trebuie să repetați totul, creând blocuri DIV individuale unice. Nu uitați să schimbați numele claselor și ID-urile DIV. În exemplul meu, este suficient să schimbați numărul zero, în noul bloc trebuie înlocuit cu 1 și așa mai departe. Această opțiune este mai complexă, dar funcționează peste tot, cu excepția browserelor foarte vechi, cum ar fi Internet Explorer

6. Care, din fericire, nu se găsește aproape niciodată pe computerele utilizatorilor.


) Am scris despre efectul pe care fișierele JavaScript îl au asupra căii critice de redare (CRP).

JavaScript este o resursă de blocare pentru parser. Aceasta înseamnă că JavaScript blochează analizarea documentului HTML în sine. Când analizatorul ajunge la eticheta ‹script› (nu contează dacă este intern sau extern), se oprește, preia fișierul (dacă este extern) și îl rulează.


Acest comportament poate fi problematic dacă încărcăm mai multe fișiere JavaScript pe o pagină, deoarece crește timpul de randare pentru prima dată, chiar dacă documentul nu depinde de fapt de acele fișiere.

Din fericire, elementul are două atribute, async și defer, care ne oferă control asupra modului în care sunt încărcate și executate fișierele externe.

Execuție normală Înainte de a înțelege diferența dintre aceste două atribute, să ne uităm la ce se întâmplă în absența lor. După cum am spus mai devreme, implicit Fișiere JavaScript
întrerupeți analizarea documentului HTML până când sunt primite și executate.


... ... ....

Să luăm un exemplu în care elementul este situat undeva în mijlocul paginii:

Iată ce se va întâmpla atunci când analizatorul procesează documentul:

Analiza HTML este întreruptă până când scriptul este descărcat și executat, crescând astfel timpul până la prima randare.

atribut asincron Async este folosit pentru a indica browserului că scriptul Pot fi
fi executat asincron.



Analizorul HTML nu trebuie să se oprească când ajunge la etichetă pentru a se încărca și a se executa. Execuția poate avea loc după ce scriptul este primit în paralel cu analizarea documentului. Atributul este disponibil numai pentru fișierele conectate extern. Dacă are acest atribut, poate fi încărcat în timp ce documentul HTML este încă analizat. Analizorul se va întrerupe pentru a executa scriptul imediat ce fișierul script este încărcat.



defer atribut

Atributul defer spune browserului că scriptul ar trebui să fie executat după ce documentul HTML a fost complet analizat.



Ca și în cazul încărcării asincrone de scripturi, fișierul poate fi încărcat în timp ce documentul HTML este analizat. Cu toate acestea, chiar dacă fișierul script este încărcat complet înainte ca analizatorul să se termine, acesta nu va fi executat până când analizatorul nu va termina de rulat.



Execuție asincronă, întârziată sau normală?

Deci, când ar trebui să utilizați asincron, amânat sau normal? Execuție JavaScript? Ca întotdeauna, depinde de situație și există mai multe întrebări care te pot ajuta să iei decizia corectă.

Unde se află elementul?

Execuția asincronă și leneșă sunt cele mai importante atunci când elementul nu se află la sfârșitul documentului. Documentele HTML sunt analizate în ordine, de la deschidere până la închidere. Dacă fișierul JavaScript extern este plasat imediat înaintea etichetei de închidere, atunci utilizarea asincronă și amânare devine mai puțin adecvată, deoarece analizatorul va fi analizat cea mai mare parte a documentului până atunci și fișierele JavaScript nu vor mai avea efect asupra acestuia.

Este scenariul autosuficient?

Pentru fișierele care nu depind de alte fișiere și/sau nu au nicio dependență, atributul asincron va fi cel mai util. Deoarece nu ne interesează când este executat fișierul, încărcarea asincronă este cea mai potrivită opțiune.

Se bazează scriptul pe un DOM complet analizat?

În multe cazuri, fișierul script conține funcții care interacționează cu DOM. Sau poate că există o dependență de un alt fișier de pe pagină. În astfel de cazuri, DOM-ul trebuie să fie complet analizat înainte ca scriptul să fie executat. De obicei, un astfel de fișier este plasat în partea de jos a paginii pentru a se asigura că totul a fost analizat pentru ca acesta să funcționeze. Cu toate acestea, într-o situație în care din anumite motive fișierul trebuie să fie localizat într-o locație diferită, atributul defer poate fi util.

Scenariul este mic și dependent?

În cele din urmă, dacă scriptul este relativ mic și/sau depinde de alte fișiere, atunci ar putea merita să îl definiți în linie. Deși codul inline blochează analizarea documentului HTML, nu ar trebui să fie o mare problemă dacă documentul este de dimensiuni mici. De asemenea, dacă depinde de alte fișiere, poate fi necesară o blocare minoră.

Suport și motoare de browser moderne

Suportul pentru atributele async și defer este foarte comun:




Este demn de remarcat faptul că comportamentul acestor atribute poate varia ușor între motoarele JavaScript. De exemplu, în V8 (utilizat în Chromium), se încearcă analizarea tuturor scripturilor, indiferent de atributele lor, într-un fir separat dedicat pentru execuția scriptului. Astfel, natura de „blocare a analizatorului” a fișierelor JavaScript ar trebui redusă la minimum în mod implicit.

Motivul pentru care am scris această postare a fost că de mai multe ori a trebuit să observ că inserarea codului de buton într-o pagină diverse servicii(de exemplu: VKontakte, Facebook, Twitter, Odnoklassniki) a dus la o încetinire vizibilă a încărcării și afișarii paginii. Este vorba despre despre cazul când se folosește conectarea javascript extern a acestor servicii sociale.
Dacă folosim statică simplă butoane grafice, nu sunt probleme, pentru că Acesta este un minim de grafice și scripturi care sunt localizate local (puteți vedea un exemplu de implementare aici http://pervushin.com/social-button-for-blog.html). Dar vedem doar icoane sociale. servicii, nu există statistici (câți oameni au „apreciat” pagina noastră). Aceste. dacă vrem să vedem statistici, va trebui să conectăm scripturi externe. Și aici merită să rețineți că la câte dintre aceste butoane ne-am conectat, browserul este obligat să descarce atât de multe scripturi externe, adică. Acest conexiuni suplimentare către servere externe.

Pentru a arăta ce se întâmplă dacă există scripturi în secțiunea de pe pagină, îmi propun să luăm în considerare o serie de exemple de testare. Voi folosi FireFox 3.6 și FireBug.

Aşa:
1) Cea mai simplă pagină cu un fișier de stil, două scripturi și trei imagini:













Și iată diagrama de încărcare a acestuia:

Vă rugăm să rețineți că toate imaginile sunt încărcate numai după ce a fost încărcat cel mai lung fișier javascript.
Am făcut în mod deliberat încărcarea dummy_css.css și dummy_js.js destul de lungă. Sunt doar două fișiere:

dummy_css.php

html,body(
marja:0;
umplutura:0;
}
.img_container(
margine:0 auto;lățime:500px;
}

dummy_js.php


var param=1;

Deci, puteți vedea că fișierul js blochează încărcarea tuturor celorlalte elemente grafice.

2) Totul este aproape la fel, dar dummy_ js. js este încărcat de pe o gazdă externă:

Situația este similară cu cea anterioară:

3) Să încercăm să schimbăm fișierele css și js din secțiunea head (css vine acum după js):







Să ne uităm la diagrama de încărcare:

Js încă blochează încărcarea imaginilor, indiferent de ce gazdă este încărcată.

4) Să creștem timpul de încărcare css la 4 secunde (cod html ca în cazul lui N3):

5) Un alt caz interesant: css este situat înainte de js, dar css durează mai mult să se încarce















Aici css-ul blochează deja încărcarea imaginilor...

6) Mutați un js înăuntru< body>
















Se vede că dummy_ js. js blochează încărcarea doar a celei de-a treia imagini, care se află în codul html după ea. Dar dacă CSS durează mai mult să se încarce, atunci va bloca încărcarea graficelor. Nu este greu de imaginat că conectarea la scripturi externe poate încetini foarte mult încărcarea și redarea paginii, mai ales dacă server la distanță

Din anumite motive, este nevoie de mult timp pentru a răspunde.

Plasarea scripturilor externe înainte Ceea ce sugerează imediat... Toate scripturile a căror încărcare nu este critică pentru pagină ar trebui plasate chiar înaintea etichetei de închidere. Dar acest lucru se poate face pentru acele scripturi în care toată logica este internă și nu există apeluri externe de la cod html

. Dacă, din codul html, unele funcții sunt apelate din scripturi care nu au fost încă încărcate, atunci astfel de situații trebuie tratate într-un mod special, deoarece trebuie să urmăriți descărcarea.




Dar mai este o problemă, permiteți-mi să vă explic cu un exemplu:
$("img").click(function() (
});
});






alert($(this).attr("src");

Dacă js înainte durează mult timp să se încarce, atunci făcând clic pe imagini până când acest script este încărcat complet nu va duce la nimic, deoarece $(document).ready() va funcționa numai după ce js este încărcat complet. Deci, dacă există o anumită logică pe pagini care implică procesarea evenimentelor, atunci această metodă nu este potrivită.

Deci, ceea ce este necesar este o modalitate de a încărca scripturile fără blocare...



Creați async.js:


script.src = "dummy_js.js";











si conecteaza-l:
Dar mai este o problemă, permiteți-mi să vă explic cu un exemplu:
$("img").click(function() (
});
});






$(document).ready(funcție() (

Dacă apelul async.js este plasat în , și nu înainte de , atunci diagrama va arăta astfel:

Dar dacă este încă mai convenabil să plasați async.js în cod, atunci ar trebui să modificați ușor conținutul async.js:
$(document).ready(funcție() (
var script = document.createElement("script");
script.src = "dummy_js.js";
}
);

document.getElementsByTagName(„cap”) .appendChild(script);