Kami penggemar Elemen Kustom di sekitar sini. Desain mereka membuat mereka sangat setuju untuk pemuatan lambat, yang bisa menjadi keuntungan bagi kinerja.
Terinspirasi oleh seorang kolega eksperimen, baru-baru ini saya mulai menulis pemuat otomatis sederhana: Setiap kali elemen khusus muncul di DOM, kami ingin memuat implementasi yang sesuai jika belum tersedia. Browser kemudian menangani pemutakhiran elemen-elemen tersebut sejak saat itu.
Kemungkinan Anda tidak benar-benar membutuhkan semua ini; biasanya ada pendekatan yang lebih sederhana. Digunakan dengan sengaja, teknik yang ditampilkan di sini mungkin masih menjadi tambahan yang berguna untuk perangkat Anda.
Untuk konsistensi, kami ingin pemuat otomatis kami juga menjadi elemen khusus โ yang juga berarti kami dapat dengan mudah mengonfigurasinya melalui HTML. Namun pertama-tama, mari identifikasi elemen kustom yang belum terselesaikan tersebut, langkah demi langkah:
class AutoLoader extends HTMLElement { connectedCallback() { let scope = this.parentNode; this.discover(scope); }
}
customElements.define("ce-autoloader", AutoLoader);
Dengan asumsi kami telah memuat modul ini di muka (menggunakan async
ideal), kita bisa menjatuhkan a <ce-autoloader>
elemen ke dalam <body>
dari dokumen kami. Itu akan segera memulai proses penemuan untuk semua elemen anak dari <body>
, yang sekarang merupakan elemen root kami. Kami dapat membatasi penemuan ke subpohon dokumen kami dengan menambahkan <ce-autoloader>
ke masing-masing elemen container โ memang, kita bahkan mungkin memiliki banyak instance untuk subpohon yang berbeda.
Tentu saja, kami masih harus menerapkannya discover
metode (sebagai bagian dari AutoLoader
kelas di atas):
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); } }
}
Di sini kami memeriksa elemen root kami bersama dengan setiap turunan (*
). Jika itu adalah elemen khusus โ seperti yang ditunjukkan oleh tag dengan tanda penghubung โ tetapi belum ditingkatkan versinya, kami akan mencoba memuat definisi yang sesuai. Menanyakan DOM dengan cara itu mungkin mahal, jadi kita harus sedikit berhati-hati. Kami dapat mengurangi beban pada utas utama dengan menunda pekerjaan ini:
connectedCallback() { let scope = this.parentNode; requestIdleCallback(() => { this.discover(scope); });
}
requestIdleCallback
belum didukung secara universal, tetapi kita dapat menggunakan requestAnimationFrame
sebagai cadangan:
let defer = window.requestIdleCallback || requestAnimationFrame; class AutoLoader extends HTMLElement { connectedCallback() { let scope = this.parentNode; defer(() => { this.discover(scope); }); } // ...
}
Sekarang kita dapat melanjutkan untuk mengimplementasikan yang hilang load
metode untuk menyuntikkan secara dinamis a <script>
elemen:
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`;
}
Perhatikan konvensi hard-code di elementURL
. itu src
URL atribut mengasumsikan ada direktori tempat semua definisi elemen khusus berada (mis <my-widget>
โ /components/my-widget.js
). Kita dapat membuat strategi yang lebih rumit, tetapi ini cukup baik untuk tujuan kita. Memindahkan URL ini ke metode terpisah memungkinkan subkelas khusus proyek bila diperlukan:
class FancyLoader extends AutoLoader { elementURL(tag) { // fancy logic }
}
Either way, perhatikan bahwa kita mengandalkan this.rootDir
. Di sinilah konfigurabilitas yang disebutkan di atas. Mari tambahkan pengambil yang sesuai:
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;
}
Anda mungkin berpikir observedAttributes
sekarang, tapi itu tidak benar-benar membuat segalanya lebih mudah. Ditambah memperbarui root-dir
saat runtime sepertinya sesuatu yang tidak akan pernah kita butuhkan.
Sekarang kita dapat โ dan harus โ mengonfigurasi direktori elemen kita: <ce-autoloader root-dir="/components">
.
Dengan ini, pemuat otomatis kami dapat melakukan tugasnya. Kecuali hanya berfungsi sekali, untuk elemen yang sudah ada saat pemuat otomatis diinisialisasi. Kami mungkin ingin memperhitungkan elemen yang ditambahkan secara dinamis juga. Di situlah MutationObserver
ikut bermain:
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();
}
Dengan cara ini, browser memberi tahu kami setiap kali elemen baru muncul di DOM โ atau lebih tepatnya, subpohon kami masing-masing โ yang kemudian kami gunakan untuk memulai ulang proses penemuan. (Anda mungkin berpendapat bahwa kami menemukan kembali elemen khusus di sini, dan Anda mungkin benar.)
Pemuat otomatis kami sekarang berfungsi penuh. Penyempurnaan di masa mendatang mungkin melihat kondisi balapan potensial dan menyelidiki pengoptimalan. Tapi kemungkinan ini cukup baik untuk sebagian besar skenario. Beri tahu saya di komentar jika Anda memiliki pendekatan yang berbeda dan kami dapat membandingkan catatan!
- Konten Bertenaga SEO & Distribusi PR. Dapatkan Amplifikasi Hari Ini.
- Platoblockchain. Intelijen Metaverse Web3. Pengetahuan Diperkuat. Akses Di Sini.
- Sumber: https://css-tricks.com/an-approach-to-lazy-loading-custom-elements/
- 1
- a
- Tentang Kami
- atas
- Akun
- sebenarnya
- menambahkan
- tambahan
- Semua
- meringankan
- memungkinkan
- sudah
- dan
- pendekatan
- membantah
- sekitar
- tersedia
- Browser
- calon
- tidak bisa
- yang
- hati-hati
- kesempatan
- memeriksa
- anak
- kelas
- bagaimana
- komentar
- membandingkan
- Kondisi
- Wadah
- Konvensi
- Sesuai
- bisa
- Tentu saja
- adat
- Mendesain
- berbeda
- penemuan
- dokumen
- Tidak
- PENGHAKIMAN
- Menjatuhkan
- dinamis
- mudah
- mudah
- Rumit
- elemen
- cukup
- kesalahan
- Eter (ETH)
- EV
- Bahkan
- Setiap
- Kecuali
- mahal
- Gagal
- penggemar
- Pertama
- dari
- sepenuhnya
- fungsionil
- masa depan
- akan
- baik
- kepala
- di sini
- HTML
- HTTPS
- ideal
- mengenali
- segera
- melaksanakan
- implementasi
- mengimplementasikan
- in
- sebagai gantinya
- menyelidiki
- IT
- JavaScript
- Pekerjaan
- Jenis
- Tahu
- Panjang
- MEMBATASI
- sedikit
- memuat
- pemuatan
- melihat
- Utama
- membuat
- MEMBUAT
- cara
- metode
- mungkin
- hilang
- modul
- lebih
- paling
- pindah
- Mozilla
- beberapa
- Perlu
- dibutuhkan
- New
- simpul
- bagian
- prestasi
- plato
- Kecerdasan Data Plato
- Data Plato
- Bermain
- plus
- potensi
- mungkin
- proses
- tujuan
- Ras
- baru-baru ini
- menghapus
- itu
- kembali
- akar
- skenario
- cakupan
- tampaknya
- terpisah
- set
- harus
- ditunjukkan
- Sederhana
- tunggal
- So
- sesuatu
- awal
- Langkah
- Masih
- strategi
- seperti itu
- Didukung
- MENANDAI
- Dibutuhkan
- teknik
- Grafik
- mereka
- hal
- Pikir
- untuk
- benar
- memperbarui
- upgrade
- URI
- URL
- us
- menggunakan
- biasanya
- melalui
- yang
- akan
- Kerja
- bekerja
- penulisan
- Anda
- zephyrnet.dll