Είμαστε θαυμαστές του Προσαρμοσμένα στοιχεία κάπου εδώ. Τους φτιάχνει ο σχεδιασμός τους ιδιαίτερα επιδέχεται τεμπέλης φόρτωσης, που μπορεί να είναι ένα όφελος για την απόδοση.
Εμπνευσμένο από ενός συναδέλφου πειράματα, άρχισα πρόσφατα να γράψω ένα απλό αυτόματο πρόγραμμα φόρτωσης: Κάθε φορά που εμφανίζεται ένα προσαρμοσμένο στοιχείο στο DOM, θέλουμε να φορτώνουμε την αντίστοιχη υλοποίηση εάν δεν είναι ακόμη διαθέσιμη. Το πρόγραμμα περιήγησης φροντίζει στη συνέχεια να αναβαθμίσει τέτοια στοιχεία από εκεί και πέρα.
Οι πιθανότητες είναι ότι δεν θα χρειαστείτε πραγματικά όλα αυτά. υπάρχει συνήθως μια απλούστερη προσέγγιση. Εάν χρησιμοποιούνται εσκεμμένα, οι τεχνικές που εμφανίζονται εδώ μπορεί να εξακολουθούν να είναι μια χρήσιμη προσθήκη στο σύνολο εργαλείων σας.
Για λόγους συνέπειας, θέλουμε το πρόγραμμα αυτόματης φόρτωσης να είναι επίσης ένα προσαρμοσμένο στοιχείο — πράγμα που σημαίνει επίσης ότι μπορούμε να το διαμορφώσουμε εύκολα μέσω HTML. Αλλά πρώτα, ας προσδιορίσουμε αυτά τα ανεπίλυτα προσαρμοσμένα στοιχεία, βήμα προς βήμα:
class AutoLoader extends HTMLElement { connectedCallback() { let scope = this.parentNode; this.discover(scope); }
}
customElements.define("ce-autoloader", AutoLoader);
Υποθέτοντας ότι έχουμε φορτώσει αυτήν την ενότητα εκ των προτέρων (χρησιμοποιώντας async
είναι ιδανικό), μπορούμε να ρίξουμε α <ce-autoloader>
στοιχείο στο <body>
του εγγράφου μας. Αυτό θα ξεκινήσει αμέσως τη διαδικασία ανακάλυψης για όλα τα θυγατρικά στοιχεία του <body>
, που αποτελεί πλέον το ριζικό μας στοιχείο. Θα μπορούσαμε να περιορίσουμε την ανακάλυψη σε ένα υποδέντρο του εγγράφου μας προσθέτοντας <ce-autoloader>
στο αντίστοιχο στοιχείο κοντέινερ αντ' αυτού — πράγματι, μπορεί να έχουμε ακόμη και πολλαπλές παρουσίες για διαφορετικά υποδέντρα.
Φυσικά, πρέπει ακόμα να το εφαρμόσουμε discover
μέθοδος (ως μέρος της AutoLoader
τάξη παραπάνω):
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); } }
}
Εδώ ελέγχουμε το ριζικό μας στοιχείο μαζί με κάθε μεμονωμένο απόγονο (*
). Εάν πρόκειται για προσαρμοσμένο στοιχείο — όπως υποδεικνύεται από ετικέτες με παύλα — αλλά δεν έχει αναβαθμιστεί ακόμη, θα προσπαθήσουμε να φορτώσουμε τον αντίστοιχο ορισμό. Η αναζήτηση στο DOM με αυτόν τον τρόπο μπορεί να είναι ακριβή, επομένως θα πρέπει να είμαστε λίγο προσεκτικοί. Μπορούμε να μειώσουμε το φορτίο στο κύριο νήμα αναβάλλοντας αυτήν την εργασία:
connectedCallback() { let scope = this.parentNode; requestIdleCallback(() => { this.discover(scope); });
}
requestIdleCallback
δεν υποστηρίζεται ακόμη καθολικά, αλλά μπορούμε να χρησιμοποιήσουμε requestAnimationFrame
ως εναλλακτική:
let defer = window.requestIdleCallback || requestAnimationFrame; class AutoLoader extends HTMLElement { connectedCallback() { let scope = this.parentNode; defer(() => { this.discover(scope); }); } // ...
}
Τώρα μπορούμε να προχωρήσουμε στην εφαρμογή των αγνοουμένων load
μέθοδος δυναμικής ένεσης α <script>
στοιχείο:
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`;
}
Σημειώστε τη σκληρά κωδικοποιημένη σύμβαση στο elementURL
. ο src
η διεύθυνση URL του χαρακτηριστικού προϋποθέτει ότι υπάρχει ένας κατάλογος όπου βρίσκονται όλοι οι ορισμοί προσαρμοσμένων στοιχείων (π.χ <my-widget>
→ /components/my-widget.js
). Θα μπορούσαμε να καταλήξουμε σε πιο περίπλοκες στρατηγικές, αλλά αυτό είναι αρκετά καλό για τους σκοπούς μας. Η ανάθεση αυτής της διεύθυνσης URL σε μια ξεχωριστή μέθοδο επιτρέπει την υποκατηγορία για συγκεκριμένο έργο όταν χρειάζεται:
class FancyLoader extends AutoLoader { elementURL(tag) { // fancy logic }
}
Σε κάθε περίπτωση, σημειώστε ότι βασιζόμαστε this.rootDir
. Εδώ μπαίνει η προαναφερθείσα δυνατότητα διαμόρφωσης. Ας προσθέσουμε έναν αντίστοιχο λήπτη:
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;
}
Μπορεί να σκέφτεστε observedAttributes
τώρα, αλλά αυτό δεν διευκολύνει πραγματικά τα πράγματα. Συν ενημέρωση root-dir
κατά το χρόνο εκτέλεσης φαίνεται σαν κάτι που δεν θα χρειαστούμε ποτέ.
Τώρα μπορούμε - και πρέπει - να διαμορφώσουμε τον κατάλογο στοιχείων μας: <ce-autoloader root-dir="/components">
.
Με αυτό, ο αυτόματος φορτωτής μας μπορεί να κάνει τη δουλειά του. Εκτός από αυτό λειτουργεί μόνο μία φορά, για στοιχεία που υπάρχουν ήδη κατά την προετοιμασία του αυτόματου φορτωτή. Μάλλον θα θέλουμε να λάβουμε υπόψη και τα δυναμικά προστιθέμενα στοιχεία. Εκεί είναι που MutationObserver
μπαίνει στο παιχνίδι:
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();
}
Με αυτόν τον τρόπο, το πρόγραμμα περιήγησης μας ειδοποιεί κάθε φορά που εμφανίζεται ένα νέο στοιχείο στο DOM — ή μάλλον, το αντίστοιχο υποδέντρο μας — το οποίο στη συνέχεια χρησιμοποιούμε για να επανεκκινήσουμε τη διαδικασία ανακάλυψης. (Μπορεί να υποστηρίξετε ότι εφευρίσκουμε εκ νέου προσαρμοσμένα στοιχεία εδώ και θα είχατε κάπως δίκιο.)
Ο αυτόματος φορτωτής μας είναι πλέον πλήρως λειτουργικός. Οι μελλοντικές βελτιώσεις ενδέχεται να εξετάσουν πιθανές συνθήκες αγώνα και να διερευνήσουν βελτιστοποιήσεις. Αλλά οι πιθανότητες είναι ότι αυτό είναι αρκετά καλό για τα περισσότερα σενάρια. Ενημερώστε με στα σχόλια εάν έχετε διαφορετική προσέγγιση και μπορούμε να συγκρίνουμε σημειώσεις!
- SEO Powered Content & PR Distribution. Ενισχύστε σήμερα.
- Platoblockchain. Web3 Metaverse Intelligence. Ενισχύθηκε η γνώση. Πρόσβαση εδώ.
- πηγή: https://css-tricks.com/an-approach-to-lazy-loading-custom-elements/
- 1
- a
- Σχετικά
- πάνω από
- Λογαριασμός
- πραγματικά
- προστιθέμενη
- Επιπλέον
- Όλα
- ανακουφίζω
- επιτρέπει
- ήδη
- και
- πλησιάζω
- Υποστηρίζουν
- γύρω
- διαθέσιμος
- πρόγραμμα περιήγησης
- υποψηφίους
- δεν μπορώ
- ο οποίος
- προσεκτικός
- πιθανότητα
- έλεγχος
- παιδί
- τάξη
- Ελάτε
- σχόλια
- συγκρίνουν
- Συνθήκες
- Δοχείο
- Σύμβαση
- Αντίστοιχος
- θα μπορούσε να
- πορεία
- έθιμο
- Υπηρεσίες
- διαφορετικές
- ανακάλυψη
- έγγραφο
- Όχι
- DOM
- Πτώση
- δυναμικά
- ευκολότερη
- εύκολα
- Λεπτομερής
- στοιχεία
- αρκετά
- σφάλμα
- Αιθέρας (ΕΤΗ)
- EV
- Even
- Κάθε
- Εκτός
- ακριβά
- Απέτυχε
- ανεμιστήρες
- Όνομα
- από
- πλήρως
- λειτουργικός
- μελλοντικός
- μετάβαση
- καλός
- κεφάλι
- εδώ
- HTML
- HTTPS
- ιδανικό
- προσδιορίσει
- αμέσως
- εφαρμογή
- εκτέλεση
- εκτελεστικών
- in
- αντί
- διερευνήσει
- IT
- το JavaScript
- Δουλειά
- Είδος
- Ξέρω
- Μήκος
- LIMIT
- λίγο
- φορτίο
- φόρτωση
- ματιά
- Κυρίως
- κάνω
- ΚΑΝΕΙ
- μέσα
- μέθοδος
- ενδέχεται να
- Λείπει
- ενότητα
- περισσότερο
- πλέον
- μετακινήσετε
- Mozilla
- πολλαπλούς
- Ανάγκη
- που απαιτούνται
- Νέα
- κόμβος
- μέρος
- επίδοση
- Πλάτων
- Πληροφορία δεδομένων Plato
- Πλάτωνα δεδομένα
- Δοκιμάστε να παίξετε
- συν
- δυναμικού
- πιθανώς
- διαδικασια μας
- σκοποί
- Αγώνας
- πρόσφατα
- αφαιρέστε
- εκείνοι
- απόδοση
- ρίζα
- σενάρια
- έκταση
- φαίνεται
- ξεχωριστό
- σειρά
- θα πρέπει να
- παρουσιάζεται
- Απλούς
- ενιαίας
- So
- κάτι
- Εκκίνηση
- Βήμα
- Ακόμη
- στρατηγικές
- τέτοιος
- υποστηριζόνται!
- TAG
- παίρνει
- τεχνικές
- Η
- τους
- πράγματα
- Σκέψη
- προς την
- αληθής
- ενημέρωση
- αναβαθμιστεί
- URI
- URL
- us
- χρήση
- συνήθως
- μέσω
- Ποιό
- θα
- Εργασία
- λειτουργεί
- γραφή
- Σας
- zephyrnet