Looge kiiremaid veebirakendusi meie põhjaliku JavaScripti koodi tükeldamise juhendi abil. Õppige dünaamilist laadimist, marsruudipõhist tükeldamist ja jõudluse optimeerimise tehnikaid.
JavaScripti koodi tükeldamine: sügav sukeldumine dünaamilisse laadimisse ja jõudluse optimeerimisse
Tänapäeva digitaalses maastikus määratletakse kasutaja esmamulje teie veebirakendusest sageli üheainsa mõõdikuga: kiirus. Aeglane, veniv veebisait võib põhjustada kasutajate frustratsiooni, kõrget põrkemäära ja otsest negatiivset mõju ärieesmärkidele. Üks olulisemaid aeglaste veebirakenduste süüdlasi on monoliitne JavaScripti pakett – üks massiivne fail, mis sisaldab kogu teie saidi koodi ja mis tuleb alla laadida, parsida ja käivitada enne, kui kasutaja saab lehega suhelda.
Siin tulebki appi JavaScripti koodi tükeldamine. See pole lihtsalt tehnika; see on fundamentaalne arhitektuuriline nihe selles, kuidas me veebirakendusi ehitame ja tarnime. Suure paketi jaotamine väiksemateks, tellitavateks tükkideks võimaldab meil dramaatiliselt parandada esialgset laadimisaega ja luua palju sujuvama kasutajakogemuse. See juhend viib teid sügavale koodi tükeldamise maailma, uurides selle põhimõisteid, praktilisi strateegiaid ja sügavat mõju jõudlusele.
Mis on koodi tükeldamine ja miks peaks see teile korda minema?
Oma olemuselt on koodi tükeldamine (ingl. *code splitting*) praktika, kus rakenduse JavaScripti kood jaotatakse mitmeks väiksemaks failiks, mida sageli nimetatakse "tükkideks" (ingl. *chunks*), mida saab laadida dünaamiliselt või paralleelselt. Selle asemel, et saata kasutajale 2MB suurune JavaScripti fail, kui ta teie avalehele satub, võite saata ainult selle lehe renderdamiseks vajaliku 200KB. Ülejäänud kood – funktsioonide jaoks nagu kasutajaprofiili leht, administraatori armatuurlaud või keerukas andmete visualiseerimise tööriist – laaditakse alla alles siis, kui kasutaja nende funktsioonide juurde navigeerib või nendega suhtleb.
Mõelge sellest kui restoranis tellimisest. Monoliitne pakett on nagu kogu mitmekäigulise menüü korraga serveerimine, olenemata sellest, kas te seda soovite või mitte. Koodi tükeldamine on *à la carte* kogemus: saate täpselt seda, mida küsite, ja täpselt siis, kui seda vajate.
Monoliitsete pakettide probleem
Lahenduse täielikuks hindamiseks peame esmalt mõistma probleemi. Üksainus suur pakett mõjutab jõudlust negatiivselt mitmel viisil:
- Suurenenud võrgu latentsus: Suuremate failide allalaadimine võtab kauem aega, eriti aeglasemates mobiilsidevõrkudes, mis on levinud paljudes maailma paikades. See esialgne ooteaeg on sageli esimene kitsaskoht.
- Pikemad parsimis- ja kompileerimisajad: Pärast allalaadimist peab brauseri JavaScripti mootor parsima ja kompileerima kogu koodibaasi. See on protsessori-intensiivne ülesanne, mis blokeerib põhilõime (ingl. *main thread*), mis tähendab, et kasutajaliides jääb hangunuks ja ei reageeri.
- Blokeeritud renderdamine: Kui põhilõim on JavaScriptiga hõivatud, ei saa see täita muid olulisi ülesandeid, nagu lehe renderdamine või kasutaja sisendile reageerimine. See viib otse halva interaktiivsuse ajani (Time to Interactive ehk TTI).
- Raisatud ressursid: Märkimisväärne osa monoliitse paketi koodist ei pruugi tüüpilise kasutajasessiooni ajal kunagi kasutusse minna. See tähendab, et kasutaja raiskab andmemahtu, akut ja protsessori võimsust koodi allalaadimiseks ja ettevalmistamiseks, mis ei paku talle mingit väärtust.
- Halvad Core Web Vitals näitajad: Need jõudlusprobleemid kahjustavad otseselt teie Core Web Vitals skoore, mis võivad mõjutada teie positsiooni otsingumootorites. Blokeeritud põhilõim halvendab esimese sisendi viivitust (First Input Delay ehk FID) ja interaktsiooni järgmise värvimiseni (Interaction to Next Paint ehk INP), samas kui viivitatud renderdamine mõjutab suurima sisulise värvimise aega (Largest Contentful Paint ehk LCP).
Tänapäevase koodi tükeldamise tuum: dünaamiline `import()`
Enamiku kaasaegsete koodi tükeldamise strateegiate taga peituv maagia on standardne JavaScripti funktsioon: dünaamiline `import()`-avaldis. Erinevalt staatilisest `import`-käsust, mida töödeldakse kompileerimise ajal ja mis ühendab moodulid kokku, on dünaamiline `import()` funktsioonilaadne avaldis, mis laadib mooduli nõudmisel.
See toimib järgmiselt:
import('/path/to/module.js')
Kui paketihaldur nagu Webpack, Vite või Rollup näeb seda süntaksit, saab see aru, et './path/to/module.js' ja selle sõltuvused tuleks paigutada eraldi tükki. `import()`-kutse ise tagastab lubaduse (Promise), mis laheneb mooduli sisuga, kui see on edukalt üle võrgu laaditud.
Tüüpiline teostus näeb välja selline:
// Eeldades, et on nupp id-ga "load-feature"
const featureButton = document.getElementById('load-feature');
featureButton.addEventListener('click', () => {
import('./heavy-feature.js')
.then(module => {
// Moodul on edukalt laaditud
const feature = module.default;
feature.initialize(); // Käivita funktsioon laaditud moodulist
})
.catch(err => {
// Käsitle laadimise ajal tekkinud vigu
console.error('Funktsiooni laadimine ebaõnnestus:', err);
});
});
Selles näites ei sisaldu `heavy-feature.js` esialgses lehe laadimises. See laaditakse serverist alles siis, kui kasutaja nupule klõpsab. See on dünaamilise laadimise põhiprintsiip.
Praktilised koodi tükeldamise strateegiad
Teadmine, "kuidas" midagi teha, on üks asi; teadmine, "kus" ja "millal" seda teha, on see, mis muudab koodi tükeldamise tõeliselt tõhusaks. Siin on kõige levinumad ja võimsamad strateegiad, mida tänapäevases veebiarenduses kasutatakse.
1. Marsruudipõhine tükeldamine
See on vaieldamatult kõige mõjukam ja laialdasemalt kasutatav strateegia. Idee on lihtne: iga leht või marsruut teie rakenduses saab oma JavaScripti tüki. Kui kasutaja külastab aadressi `/home`, laaditakse ainult avalehe kood. Kui ta navigeerib aadressile `/dashboard`, laaditakse dünaamiliselt armatuurlaua JavaScript.
See lähenemine on täielikus kooskõlas kasutaja käitumisega ja on uskumatult tõhus mitmeleheliste rakenduste (isegi ühe lehe rakenduste ehk SPA-de) puhul. Enamikul tänapäevastel raamistikel on selleks sisseehitatud tugi.
Näide Reactiga (`React.lazy` ja `Suspense`)
React muudab marsruudipõhise tükeldamise sujuvaks tänu `React.lazy`-le komponentide dünaamiliseks importimiseks ja `Suspense`-le varu-kasutajaliidese (nagu laadimisikoon) kuvamiseks, kuni komponendi koodi laaditakse.
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
// Impordi staatiliselt komponendid tavaliste/esialgsete marsruutide jaoks
import HomePage from './pages/HomePage';
// Impordi dünaamiliselt komponendid harvemate või raskemate marsruutide jaoks
const DashboardPage = lazy(() => import('./pages/DashboardPage'));
const AdminPanel = lazy(() => import('./pages/AdminPanel'));
function App() {
return (
Lehe laadimine...
Näide Vue'ga (asünkroonsed komponendid)
Vue ruuteril on esmaklassiline tugi komponentide laisklaadimiseks, kasutades dünaamilist `import()`-süntaksit otse marsruudi definitsioonis.
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
const routes = [
{
path: '/',
name: 'Home',
component: Home // Laaditakse esialgu
},
{
path: '/about',
name: 'About',
// Marsruudi tasemel koodi tükeldamine
// See genereerib selle marsruudi jaoks eraldi tüki
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;
2. Komponendipõhine tükeldamine
Mõnikord on isegi ühe lehe piires suuri komponente, mis ei ole kohe vajalikud. Need on ideaalsed kandidaadid komponendipõhiseks tükeldamiseks. Näideteks on:
- Modaalaknad või dialoogid, mis ilmuvad pärast seda, kui kasutaja klõpsab nupule.
- Keerulised graafikud või andmete visualiseerimised, mis asuvad lehe nähtavast osast allpool.
- Rikkaliku teksti redaktor, mis ilmub alles siis, kui kasutaja klõpsab "muuda".
- Videopleieri teek, mida pole vaja laadida enne, kui kasutaja klõpsab esitusikoonil.
Teostus sarnaneb marsruudipõhise tükeldamisega, kuid selle käivitab kasutaja interaktsioon, mitte marsruudi muutus.
Näide: modaalakna laadimine klõpsamisel
import React, { useState, Suspense, lazy } from 'react';
// Modaalakna komponent on defineeritud eraldi failis ja see paigutatakse eraldi tükki
const HeavyModal = lazy(() => import('./components/HeavyModal'));
function MyPage() {
const [isModalOpen, setIsModalOpen] = useState(false);
const openModal = () => {
setIsModalOpen(true);
};
return (
Tere tulemast lehele
{isModalOpen && (
Modaali laadimine... }>
setIsModalOpen(false)} />
)}