Det asynkrone script i sidebjælken virker ikke. Bedst fungerende asynkron javascript-indlæsning

Bemærk: Nedenfor er en oversættelse af en artikel fra Steve Souders (forfatter af de berømte Yahoo! tips vedrørende klientydelse) "Kobling af async scripts". Steve analyserer indlæsningsadfærden af ​​JavaScript-filer og foreslår flere måder at omgå deres blokeringsegenskaber. Mine kommentarer nedenfor er i kursiv.

Det meste af mit arbejde er i På det sidste var afsat til asynkron indlæsning af eksterne scripts. Hvis scripts indlæses i normal rækkefølge (), blokerer de indlæsningen af ​​alle andre sidekomponenter ( V seneste versioner Dette er ikke tilfældet i Firefox og Safari, men vi taler hovedsageligt om 70% af IE-brugere) og blokerer gengivelsen af ​​hele den del af siden, der er placeret under kaldet til scripts i HTML-koden. Dette kan ses på testsiden, vi placerer scripts nedenfor for eksempel ved at bruge dynamisk skabelse objekter efter det kombinerede hændelsesvindue.onload er udløst) forhindrer denne browseradfærd, hvilket fremskynder sideindlæsning.

Det eneste problem med at indlæse scripts asynkront er deres interaktion med interne ( inline) sidescripts ( samt med andre eksterne scripts), som bruger variabler defineret i et eksternt script. Hvis et eksternt script indlæses asynkront uden kendskab til HTML-sidens interne kode, så er det meget muligt, at ( og det vil forekomme i de fleste tilfælde), når nogle variabler ikke vil blive defineret på tidspunktet for deres brug. Derfor skal du sikre dig, at eksterne scripts indlæst asynkront og interne sidescripts er koblet: interne scripts udføres ikke, før asynkrone scripts er fuldt indlæst.

Der er flere ( standard) måder at forbinde asynkront indlæste scripts med anden JavaScript-kode:

  • vindue indlæst. Udførelse af intern JavaScript-kode kan knyttes til vinduets onload-hændelse. Det er meget nemt at bruge, men nogle af scripts kan udføres tidligere.
  • onreadystatechange i scriptet. Den interne kode kan være bundet til onreadystatechange og/eller onload-hændelser. (Det vil være nødvendigt at bruge begge muligheder for at dække alt populære browsere.) I dette tilfælde vil der være mere kode, det vil være mere komplekst, men der vil være en garanti for, at det vil blive udført umiddelbart efter indlæsning af de tilsvarende eksterne filer.
  • Indbyggede opkald. Eksterne scripts kan modificeres til at inkludere til allersidst et kald til et lille stykke kode, der kalder den tilsvarende funktion fra den interne kode. Det hele er fantastisk, hvis eksterne og interne scripts er udviklet af det samme team. Men i tilfælde af brug af tredjepartsudviklinger, vil dette ikke give al den nødvendige fleksibilitet til at forbinde eksterne scripts med intern kode.

I denne artikel dækker jeg samtidigt (ingen ordspil!) to spørgsmål: hvordan asynkrone scripts fremskynder sideindlæsning, og hvordan du kan kombinere asynkrone scripts og interne ved hjælp af en modificeret version af loaderen fra John Resig ( af jQuery) er en dobbelt script-tagskabelon. En illustration af dette er mit seneste arbejde med at sortere UA Profiler-resultater. Jeg gjorde det ved hjælp af sorteringsscriptet fra Stuart Langridge. På cirka 5 minutter var jeg i stand til at tilføje hans script til en side for at sortere resultattabellen. Med lidt mere tid var jeg i stand til at få dette script til at indlæse asynkront og fremskynde sideindlæsningen med over 30 % ved hjælp af den asynkrone script-docking-teknik.

Regelmæssige script-opkald

Jeg tilføjede oprindeligt Stuart Langridges sorteringsscript til UA Profiler-siden på sædvanlig måde(via ), dette kan ses i varianten med et almindeligt script-kald. Ladningsdiagrammet er vist i fig. 1.

Ris. 1. Diagram over indlæsning af scripts i det sædvanlige tilfælde.

Selvom sorteringen af ​​dataene i tabellen virkede, gjorde det mig ikke mere glad, fordi sideindlæsningen blev langsommere. I fig. 1 viser tydeligt, hvordan min version af scriptet (navngivet sorttable-async.js) blokerer alle andre HTTP-anmodninger på siden (især arrow-right-20x9.gif), hvilket bremser sideindlæsningen. Alle indlæsningsdiagrammer blev taget med Firebug 1.3 beta. I denne version af Firebug viser den røde linje onload-hændelsen. (Og den blå linje svarer til hændelsen domcontentloaded.) For versionen med et almindeligt script-kald udløses onload-hændelsen ved 487 millisekunder.

Sorttable-async.js-scriptet er ikke nødvendigt for indledningsvis at gengive siden: kolonner kan kun sorteres efter selve kolonnerne er blevet gengivet. Denne situation (eksterne scripts, der ikke bruges til indledningsvis at gengive siden) er kandidat nummer 1 til implementering af asynkron indlæsning. Indstillingen med asynkron indlæsning af scripts forbinder dette script ved at bruge DOM-metoder til at oprette et nyt script tag:

var script = document.createElement("script"); script.src = "sorttable-async.js"; script.text = "sorttable.init()"; // dette er forklaret i næste afsnit document.getElementsByTagName("head").appendChild(script);

HTTP-indlæsningsdiagrammet for asynkron indlæsning af scripts er vist i fig. 2. Det er værd at bemærke, hvordan den asynkrone tilgang forhindrer blokeringsadfærd: sorttable-async.js og arrow-right-20x9.gif indlæses parallelt. Dette reducerer samlet tid indlæsningstid er 429 ms.

Ris. 2. Diagram over indlæsning af scripts i det asynkrone tilfælde

Prøve dobbelt script af John Resig

Giver dig mulighed for at fremskynde sideindlæsning, men i dette tilfælde er der stadig plads til forbedringer. Som standard kalder sorteringsscriptet sig selv ved at vedhæfte sorttable.init() til handleren onload begivenheder for dette script. Nogle præstationsforbedringer ( og kodereduktion) kan opnås ved at kalde sorttable.init() inde i et script-tag for at kalde det umiddelbart efter det eksterne script er indlæst ( tilsluttet via src). I dette tilfælde bruger jeg en enkelt funktion som "API", men jeg gætter på, at dette tilfælde illustrerer et maksimalt udvideligt mønster, der giver dig mulighed for at bruge eksternt modul uden nogen antagelser om det videre brug (klassisk situation med brug af JavaScript-logik fra eksterne udviklere).

Jeg har allerede beskrevet tre metoder til at forbinde intern kode med asynkron indlæsning af eksterne scripts: vindue onload, onreadystatechange for scriptet og en handler indbygget i scriptet. I stedet brugte jeg en teknik fra John Resig – det dobbelte script tag-mønster. John beskriver, hvordan man kobler interne scripts til indlæsning ekstern fil på følgende måde:

jQuery("p").addClass("pæn");

I dette tilfælde udløses koden indeni kun efter indlæsning ( og initialisering) eksternt script er afsluttet. Denne script-link-tilgang har flere åbenlyse fordele:

  • enklere: ét script-tag i stedet for to
  • mere gennemsigtig: sammenhængen mellem intern og ekstern kode er mere indlysende
  • sikrere: hvis det eksterne script ikke indlæses, vil den interne kode ikke blive eksekveret, hvilket vil forhindre fejl relateret til udefinerede variabler i at dukke op

Dette er et fantastisk mønster til at indlæse eksterne scripts asynkront. Men for at bruge det bliver vi nødt til at foretage ændringer i både den interne kode og den eksterne fil. Til den interne kode var jeg nødt til at tilføje den tredje linje, der allerede er nævnt ovenfor, som afslører egenskaben script.text. For at fuldføre dockingprocessen skal du tilføje sorttable-async.js til slutningen:

var scripts = document.getElementsByTagName("script"); var cntr = scripts.length; while (cntr) ( var curScript = scripts; if (-1 != curScript.src.indexOf("sorttable-async.js")) ( eval(curScript.innerHTML); break; ) cntr--; )

Denne kode gennemgår alle scripts på siden, finder den nødvendige blok, som skal indlæse sig selv (i dette tilfælde er det et script med en src indeholdende sorttable-async.js). Den udfører derefter koden, der er tilføjet til scriptet (i dette tilfælde sorttable.init()) og kalder dermed sig selv. (Lille bemærkning: selvom teksten i det blev tilføjet ved indlæsning af scriptet vha tekst egenskaber, tilgås den ved hjælp af egenskaben innerHTML. Dette er nødvendigt for at sikre kompatibilitet på tværs af browsere.) Ved at bruge denne optimering kan vi indlæse en ekstern scriptfil uden at blokere indlæsningen af ​​andre ressourcer og udføre den, der er linket til dette script intern kode.

Det er også værd at bemærke, at den beskrevne teknik kun kan erstatte direkte modifikation af et eksternt script. Hvis en sådan ændring ikke er mulig, kan vi kun bruge installationen af ​​en belastningskontrol med et interval:

var _on_ready_execution = setInterval(function() (if (typeof urchinTracker === funktion) (urchinTracker(); clearInterval(_on_ready_execution); ) ), 10);

Denne tilgang er allerede beskrevet i bogen "Overclock your website", men det indebærer yderligere belastning af processoren for konstant kontrol det nødvendige script er klar og virker ikke, hvis den eksterne fil ikke er tilgængelig: kontrollen fortsætter med at køre.

Men i tilfælde af kontrol efter interval behøver vi slet ikke at ændre den eksterne fil, men i tilfælde af dobbelt brug af script-tagget er dette simpelthen nødvendigt. Intervalkontrol kan forbedres, hvis du efter et stykke tid (f.eks. 5-10 sekunder) genstarter download af den eksterne fil (ændrer det originale script-tag ved hjælp af en unik GET-parameter), og efter flere mislykkede genstarter stopper downloader helt (måske med nogle så en fejlmeddelelse).

Doven indlæsning

Den samlede indlæsningstid kan reduceres yderligere ved at bruge " doven indlæsning» script (indlæs det dynamisk som en del af onload-hændelseshandleren). Et eksempel på denne adfærd er placeret på siden med

Hilsen, venner! Vidste du, at indlæsning af JavaScript er en af ​​de mest flaskehalse i webstedets ydeevne? I dag er min hovedopgave at forklare, hvad et script er, og hvordan det påvirker webstedets hastighed og ydeevne.

En browser, der indlæser et script-tag, stopper med at gengive siden, indtil scriptet er indlæst og udført. Siden er blokeret, og browseren reagerer ikke på brugerhandlinger i et par sekunder. Forsinkelsestiden afhænger af flere faktorer:

  • konfigurationer,
  • Internetforbindelse hastighed,
  • filstørrelse og andet...

Af denne grund anbefaler Google PageSpeed ​​​​Insights websitehastighedsanalysator at fjerne fra toppen af ​​siden JavaScript-kode, blokerer dens visning. En god praksis er at placere scripts i bunden af ​​sitet, for eksempel før det afsluttende tag eller opsætte asynkron indlæsning.

Hvis scriptkoden påvirker visningen af ​​den øverste del af webstedet, skal du ikke placere den i separat fil, og integrere direkte i HTML.

JS kan ændre webstedets indhold og endda omdirigere til en anden URL. I dette tilfælde vil tilslutning af scriptet i slutningen af ​​dokumentet føre til effekten af ​​"twitching" på siden, indlæsning af nye eller ændring af eksisterende elementer øverst.

Anvendelse af asynkron- og defer-attributterne på script-tagget

Lad os finde ud af, hvad asynkront og udskudt arbejde i JavaScript er, og hvad den grundlæggende forskel er mellem asynkron- og defer-attributterne. Men lad os først se på rækkefølgen af ​​behandling af et dokument ved hjælp af et normalt script-tag.

1 < src = "example.js" >

I klart eksempel Jeg vil bruge følgende symboler:

— sidebehandling
- script indlæsning
- script udførelse

Således foregår behandlingssekvensen i henhold til følgende skema:

Parsing af HTML-koden afbrydes, mens scriptet indlæses og udføres, hvorefter det fortsætter. Der er en forsinkelse i visningen af ​​websiden.

udskyde attribut

Defer-attributten gør det muligt for browseren at begynde at downloade js-filer parallelt uden at stoppe yderligere behandling af siden. De henrettes efter fuld analyse objektmodel document (fra den engelske Document Object Model, forkortet DOM), mens browseren garanterer konsistens baseret på den rækkefølge, filerne forbindes i.

1 < defer src = "example.js" >

asynkron attribut

Understøttelse af async-attributten dukkede op i HTML5, det giver browseren mulighed for at downloade js-filer parallelt og udføre dem umiddelbart efter download uden at vente på, at resten af ​​siden skal behandles.

1 < async src = "example.js" >

Behandlingssekvensdiagram:

Dette er en asynkron download. Denne egenskab anbefales til brug i scripts, der ikke har en væsentlig indflydelse på visningen af ​​dokumentet. Disse omfatter statistikindsamlingstællere ( Google Analytics, Yandex Metrica), reklamenetværkskoder (Yandex Advertising Network, Google AdSense), knapper sociale netværk og så videre.

Webstedets indlæsningshastighed er en af ​​rangeringsfaktorerne i Google.

Asynkron JavaScript-forbindelse reducerer sideindlæsningstider ved at eliminere latens. Sammen med dette anbefaler jeg at komprimere og flette js-filer til én, for eksempel ved hjælp af . Brugere kan lide hurtige sider 😎

Moderne websider er tungt fyldt med javascript-filer. Dette fører til langsommere indlæsning og efterfølgende visning af siden. Under de værste forhold skal den besøgende vente op til 30 sekunder.

Vi speeder op indlæser html sider

Moderne brug af JavaScript

Moderne websider er tungt fyldt med javascript-filer. Dette fører til langsommere indlæsning og efterfølgende visning af siden. Under de værste forhold (langsom internetforbindelse, mange javascript filer) en besøgende skal vente op til 30 sekunder.

HTML er designet på en sådan måde, at en webside indlæses ved synkront (linje for linje) at indlæse alle de elementer, der er inkluderet i HTML-koden.

Der er en løsning: sæt Java-strengene til sidst html dokument(de vil derfor blive indlæst efter hele siden er tegnet) og først derefter vil indholdet af blokkene blive vist i på de rigtige steder. Det kaldes .

Alle seriøse projekter i dag forsøger at skifte til ny teknologi Downloads. Desuden er det helt nemt.

Der er flere tilgange. Jeg starter i rækkefølge.

< script src= "//www.site.ru/script.js" type= "text/javascript" >

HTML5-standarden understøtter muligheden for at indlæse scripts asynkront, hvilket betydeligt kan fremskynde den samlede sidehentningstid. Du skal blot tilføje asynkron eller udskyde .

< script async src= "//www.site.ru/script.js" type= "text/javascript" >

< script defer src= "//www.site.ru/script.js" type= "text/javascript" >

Hvad er forskellen mellem asynkron- og defer-attributterne?

I begge tilfælde får vi asynkron indlæsning af scripts. Den eneste forskel er det øjeblik, hvor scriptet begynder at køre. Et script med attributten async vil blive udført så hurtigt som muligt efter det fuld last, men før vinduesobjektet indlæses. Hvis defer-attributten bruges, vil scriptet ikke overtræde rækkefølgen af ​​dets eksekvering i forhold til andre scripts, og dets eksekvering vil finde sted efter siden er fuldt indlæst og parset, men før DOMContentLoaded-hændelsen for dokumentobjektet.

Desværre virker denne mekanisme i øjeblikket ikke i alle browsere (især IE). Virker heller ikke, hvis der er document.write-linjer i script.js-filen.

Som alle eksperter ved, er Google særlig opmærksom på indlæsningshastigheden på websteder og reducerer langsomme. Søgeresultater. For at hjælpe har Google udviklet et særligt script, som du kan lave asynkron javascript-indlæsning med.

For at bruge, skal du blot udskifte


Og tilslut script-filen extsrc.js

Det bliver sådan her:

< script src= "//extsrcjs.googlecode.com/svn/trunk/extsrc.js" > < script extsrc= "...." >

Desværre virker denne metode heller ikke for filer med document.write

En universel metode til alle browsere. Fungerer endda med document.write

På det sted på siden, hvor vi faktisk skal vise vores element, skal du oprette en tom div-blok:

< div id= "script_block" class = "script_block" >

Til allersidst på siden, før vi indsætter et script til asynkron indlæsning af filer:

< div id= "script_ad" class = "script_ad" style= "display:none;" >Her er enhver fil eller script, der skal indlæses.< script type= "text/javascript" >// flyt den til reelle stilling vise dokument. getElementById("script_block" ) . appendChild(dokument. getElementById("script_ad" ) ); // vis dokument. getElementById("script_ad" ) . stil. display = "blok" ;

I de ældste versioner af IE (6 og derunder) virker asynkron indlæsning desværre ikke, men der er praktisk talt ingen sådanne brugere længere. Alle andre browsere og tjenester bruger moderne accelereret belastning web sider.

HTML er designet på en sådan måde, at websiden indlæses sekventielt linje for linje, og indlæser på skift alle de elementer, der er inkluderet i html-koden. Og hvis en af ​​dem ikke er tilgængelig (f.eks. læses javaScript fra et eksternt websted ikke), stopper yderligere indlæsning af webstedet.

Når ulæselig JS er øverst på siden, kan den besøgende muligvis ikke se noget som helst.

Derfor, når du bruger JavaScript fra tredjepartssider på din hjemmeside, for eksempel til at vise annoncer, er det meget tilrådeligt at indlæse dem asynkront. I dette tilfælde vil tredjeparts JS ikke forsinke indlæsningen og visningen af ​​dit websted.

Desværre ikke alle annoncenetværk giver mulighed for asynkront at indlæse scripts. Derfor vil jeg i denne artikel fortælle dig, hvordan du ændrer synkron indlæsningskode til asynkron. Hvis ejeren af ​​dette script ikke giver denne mulighed.

Standard synkron JS-belastning

Opkald til et script fra en ekstern server ser typisk sådan ud:

Asynkron script-indlæsning som Google/Adsense gør

Jeg fik ideen fra Google/Adsense. For at scriptet kan indlæses asynkront fra resten af ​​HTML-koden, skal du tilføje asynkron til opkaldskoden.

Og nu for at koden skal indlæses asynkront, skulle vores scriptkald fra den eksterne server se sådan ud:

Som du kan se, er alt enkelt. Sandt nok virker dette kun i browsere, der understøtter HTML5-standarden. På tidspunktet for skrivning af denne artikel er der et absolut flertal af sådanne browsere.

Den foreslåede mulighed er ikke 100 % universel. Mange scripts holder simpelthen op med at fungere efter at have foretaget disse ændringer. Ifølge anmeldelser på internettet virker denne metode ikke, hvis elementet bruges i scriptet dokument.skrive.

Pålidelig asynkron indlæsningsmulighed

Hvis den første foreslåede mulighed ikke virker for dig. Så udnyt følgende anbefalinger. Dette er i det væsentlige doven indlæsning. Da det rigtige script-kald opstår til allersidst HTML-sider, altså når alt det nødvendige indhold på siden allerede er på skærmen.

På det sted på siden, hvor du vil vise resultatet JavaScript arbejde du skal oprette en tom div-blok:

Så i slutningen af ​​siden før det afsluttende BODY tag indsætter vi et script til asynkron indlæsning:

// JavaScript, der skal indlæses asynkront // flyt det til den faktiske visningsposition document.getElementById("script_block_0").appendChild(document.getElementById("script_ad_0")); // show document.getElementById("script_ad_0").style.display = "blok";

Hvis der er flere reklameblokke, skal du for hver af dem gentage alt og skabe unikke individuelle DIV-blokke. Glem ikke at ændre klassenavne og DIV-id'er. I mit eksempel er det nok at ændre tallet nul, i den nye blok skal det udskiftes med 1, og så videre.

Denne mulighed er mere kompleks, men den virker overalt undtagen for meget gamle browsere som f.eks Internet Explorer 6. Som heldigvis næsten aldrig findes på brugernes computere.

Der er en vej ud: Placer Javascript-linjerne i slutningen af ​​html-dokumentet (derfor vil de blive indlæst efter hele siden er tegnet) og først derefter vil indholdet af blokkene blive vist de rigtige steder. Det kaldes . Alle seriøse projekter i dag forsøger at skifte til ny læsseteknologi så hurtigt som muligt. Desuden er det helt nemt.

Der er flere tilgange. Jeg starter i rækkefølge.

script src= type= "tekst/javascript" >

Asynkron indlæsning af HTML5-script

HTML5-standarden understøtter muligheden for at indlæse scripts asynkront, hvilket betydeligt kan fremskynde den samlede sidehentningstid. Du skal blot tilføje asynkron eller udskyde .

< script async src= "http://www.site.ru/script.js" type= "text/javascript" >

< script defer src= "http://www.site.ru/script.js" type= "text/javascript" >

Hvad er forskellen mellem asynkron- og defer-attributterne?

I begge tilfælde får vi asynkron indlæsning af scripts. Den eneste forskel er det øjeblik, hvor scriptet begynder at køre. Et script med attributten async vil blive udført så hurtigt som muligt efter det er fuldt indlæst, men før vinduesobjektet indlæses. Hvis defer-attributten bruges, vil scriptet ikke overtræde rækkefølgen af ​​dets eksekvering i forhold til andre scripts, og dets eksekvering vil finde sted efter siden er fuldt indlæst og parset, men før DOMContentLoaded-hændelsen for dokumentobjektet.

Desværre virker denne mekanisme i øjeblikket ikke i alle browsere (især IE). Virker heller ikke, hvis der er document.write-linjer i script.js-filen.

Asynkron belastning javascript script fra Google

Som alle eksperter ved, er Google særlig opmærksom på indlæsningshastigheden på websteder og sænker langsomme i søgeresultaterne. For at hjælpe har Google udviklet et særligt script, som du kan lave asynkron javascript-indlæsning med.

For at bruge, skal du blot udskifte


Og tilslut script-filen extsrc.js

Det bliver sådan her:

< script src= "http://extsrcjs.googlecode.com/svn/trunk/extsrc.js" > < script extsrc= "...." >

Desværre virker denne metode heller ikke for filer med document.write

Arbejder bedst asynkront indlæser javascript

En universel metode til alle browsere. Fungerer endda med document.write

På det sted på siden, hvor vi faktisk skal vise vores element, skal du oprette en tom div-blok:

< div id= "script_block" class = "script_block" >

Til allersidst på siden, før vi indsætter et script til asynkron indlæsning af filer:

< div id= "script_ad" class = "script_ad" style= "display:none;" >Her er enhver fil eller script, der skal indlæses.< script type= "text/javascript" >// flyt det til det faktiske visningspositionsdokument. getElementById("script_block" ) . appendChild(dokument. getElementById("script_ad" ) ); // vis dokument. getElementById("script_ad" ) . stil. display = "blok" ;

I de ældste versioner af IE (6 og derunder) virker asynkron indlæsning desværre ikke, men der er praktisk talt ingen sådanne brugere længere. Alle andre browsere og tjenester bruger med succes moderne accelereret indlæsning af websider.