Jesteśmy fanami Elementy niestandardowe dookoła. Tworzy je ich konstrukcja szczególnie podatne na leniwe ładowanie, co może być dobrodziejstwem dla wydajności.
Zainspirowany kolegi eksperymentów, niedawno zabrałem się za napisanie prostego modułu automatycznego ładowania: za każdym razem, gdy w DOM pojawia się niestandardowy element, chcemy załadować odpowiednią implementację, jeśli nie jest jeszcze dostępna. Następnie przeglądarka zajmuje się aktualizacją takich elementów.
Są szanse, że tak naprawdę nie będziesz tego wszystkiego potrzebować; zwykle jest prostsze podejście. Użyte celowo techniki pokazane tutaj mogą nadal być użytecznym dodatkiem do Twojego zestawu narzędzi.
Aby zapewnić spójność, chcemy, aby nasz moduł automatycznego ładowania był również elementem niestandardowym — co oznacza również, że możemy go łatwo skonfigurować za pomocą kodu HTML. Ale najpierw zidentyfikujmy krok po kroku te nierozwiązane elementy niestandardowe:
class AutoLoader extends HTMLElement { connectedCallback() { let scope = this.parentNode; this.discover(scope); }
}
customElements.define("ce-autoloader", AutoLoader);
Zakładając, że załadowaliśmy ten moduł z góry (używając async
jest idealny), możemy odrzucić a <ce-autoloader>
element do <body>
naszego dokumentu. Spowoduje to natychmiastowe rozpoczęcie procesu wykrywania wszystkich elementów podrzędnych programu <body>
, który teraz stanowi nasz element główny. Możemy ograniczyć wykrywanie do poddrzewa naszego dokumentu, dodając <ce-autoloader>
zamiast tego do odpowiedniego elementu kontenera — w rzeczywistości możemy nawet mieć wiele instancji dla różnych poddrzew.
Oczywiście musimy to jeszcze wdrożyć discover
metoda (w ramach AutoLoader
klasa powyżej):
discover(scope) { let candidates = [scope, ...scope.querySelectorAll("*")]; for(let el of candidates) { let tag = el.localName; if(tag.includes("-") && !customElements.get(tag)) { this.load(tag); } }
}
Tutaj sprawdzamy nasz element główny wraz z każdym potomkiem (*
). Jeśli jest to element niestandardowy — na co wskazują tagi z łącznikiem — ale jeszcze nie zaktualizowany, spróbujemy załadować odpowiednią definicję. Zapytanie DOM w ten sposób może być kosztowne, więc powinniśmy być trochę ostrożni. Możemy zmniejszyć obciążenie głównego wątku, odkładając tę pracę:
connectedCallback() { let scope = this.parentNode; requestIdleCallback(() => { this.discover(scope); });
}
requestIdleCallback
nie jest jeszcze powszechnie obsługiwany, ale możemy go używać requestAnimationFrame
jako awaria:
let defer = window.requestIdleCallback || requestAnimationFrame; class AutoLoader extends HTMLElement { connectedCallback() { let scope = this.parentNode; defer(() => { this.discover(scope); }); } // ...
}
Teraz możemy przejść do realizacji brakujących load
metoda dynamicznego wstrzykiwania a <script>
element:
load(tag) { let el = document.createElement("script"); let res = new Promise((resolve, reject) => { el.addEventListener("load", ev => { resolve(null); }); el.addEventListener("error", ev => { reject(new Error("failed to locate custom-element definition")); }); }); el.src = this.elementURL(tag); document.head.appendChild(el); return res;
} elementURL(tag) { return `${this.rootDir}/${tag}.js`;
}
Zwróć uwagę na zakodowaną konwencję w elementURL
, src
adres URL atrybutu zakłada, że istnieje katalog, w którym znajdują się wszystkie definicje elementów niestandardowych (np <my-widget>
→ /components/my-widget.js
). Moglibyśmy wymyślić bardziej rozbudowane strategie, ale to wystarczy do naszych celów. Przeniesienie tego adresu URL do oddzielnej metody pozwala w razie potrzeby na podklasę specyficzną dla projektu:
class FancyLoader extends AutoLoader { elementURL(tag) { // fancy logic }
}
Tak czy inaczej, zauważ, że polegamy na this.rootDir
. W tym miejscu pojawia się wspomniana wyżej konfigurowalność. Dodajmy odpowiedni moduł pobierający:
get rootDir() { let uri = this.getAttribute("root-dir"); if(!uri) { throw new Error("cannot auto-load custom elements: missing `root-dir`"); } if(uri.endsWith("/")) { // remove trailing slash return uri.substring(0, uri.length - 1); } return uri;
}
Być może myślisz o observedAttributes
teraz, ale to wcale nie ułatwia sprawy. Do tego aktualizacja root-dir
w czasie wykonywania wydaje się czymś, czego nigdy nie będziemy potrzebować.
Teraz możemy — i musimy — skonfigurować nasz katalog elementów: <ce-autoloader root-dir="/components">
.
Dzięki temu nasza automatyczna ładowarka może wykonać swoją pracę. Z wyjątkiem tego, że działa tylko raz, dla elementów, które już istnieją podczas inicjowania modułu automatycznego ładowania. Prawdopodobnie będziemy chcieli uwzględnić również dynamicznie dodawane elementy. To tam gdzie MutationObserver
wchodzi w grę:
connectedCallback() { let scope = this.parentNode; defer(() => { this.discover(scope); }); let observer = this._observer = new MutationObserver(mutations => { for(let { addedNodes } of mutations) { for(let node of addedNodes) { defer(() => { this.discover(node); }); } } }); observer.observe(scope, { subtree: true, childList: true });
} disconnectedCallback() { this._observer.disconnect();
}
W ten sposób przeglądarka powiadamia nas o pojawieniu się nowego elementu w DOM — a raczej w naszym odpowiednim poddrzewie — którego następnie używamy do ponownego uruchomienia procesu wykrywania. (Możesz twierdzić, że wymyślamy tutaj niestandardowe elementy na nowo, i będziesz miał trochę racji).
Nasza automatyczna ładowarka jest teraz w pełni funkcjonalna. Przyszłe ulepszenia mogą sprawdzać potencjalne warunki wyścigu i badać optymalizacje. Ale są szanse, że jest to wystarczające dla większości scenariuszy. Daj mi znać w komentarzach, jeśli masz inne podejście i możemy porównać notatki!
- Dystrybucja treści i PR oparta na SEO. Uzyskaj wzmocnienie już dziś.
- Platoblockchain. Web3 Inteligencja Metaverse. Wzmocniona wiedza. Dostęp tutaj.
- Źródło: https://css-tricks.com/an-approach-to-lazy-loading-custom-elements/
- 1
- a
- O nas
- powyżej
- Konto
- faktycznie
- w dodatku
- dodatek
- Wszystkie kategorie
- łagodzić
- pozwala
- już
- i
- podejście
- argumentować
- na około
- dostępny
- przeglądarka
- kandydatów
- nie może
- który
- ostrożny
- duża szansa,
- ZOBACZ
- dziecko
- klasa
- jak
- komentarze
- porównać
- Warunki
- Pojemnik
- Konwencja
- Odpowiedni
- mógłby
- kurs
- zwyczaj
- Wnętrze
- różne
- odkrycie
- dokument
- Nie
- DOM
- Spadek
- dynamicznie
- łatwiej
- z łatwością
- Opracować
- Elementy
- dość
- błąd
- Eter (ETH)
- EV
- Parzyste
- Każdy
- Z wyjątkiem
- drogi
- Failed
- Fani
- i terminów, a
- od
- w pełni
- funkcjonalny
- przyszłość
- będzie
- dobry
- głowa
- tutaj
- HTML
- HTTPS
- idealny
- zidentyfikować
- natychmiast
- wdrożenia
- realizacja
- wykonawczych
- in
- zamiast
- badać
- IT
- JAVASCRIPT
- Praca
- Uprzejmy
- Wiedzieć
- Długość
- LIMIT
- mało
- załadować
- załadunek
- Popatrz
- Główny
- robić
- WYKONUJE
- znaczy
- metoda
- może
- brakujący
- moduł
- jeszcze
- większość
- ruch
- Mozilla
- wielokrotność
- Potrzebować
- potrzebne
- Nowości
- węzeł
- część
- jest gwarancją najlepszej jakości, które mogą dostarczyć Ci Twoje monitory,
- plato
- Analiza danych Platona
- PlatoDane
- Grać
- plus
- potencjał
- prawdopodobnie
- wygląda tak
- cele
- Wyścig
- niedawno
- usunąć
- osób
- powrót
- korzeń
- scenariusze
- zakres
- wydaje
- oddzielny
- zestaw
- powinien
- pokazane
- Prosty
- pojedynczy
- So
- coś
- początek
- Ewolucja krok po kroku
- Nadal
- strategie
- taki
- Utrzymany
- TAG
- trwa
- Techniki
- Połączenia
- ich
- rzeczy
- Myślący
- do
- prawdziwy
- aktualizowanie
- zmodernizowane
- URI
- URL
- us
- posługiwać się
- zazwyczaj
- przez
- który
- będzie
- Praca
- działa
- pisanie
- Twój
- zefirnet