Maison > interface Web > tutoriel CSS > Une approche du chargement paresseux des éléments personnalisés

Une approche du chargement paresseux des éléments personnalisés

Joseph Gordon-Levitt
Libérer: 2025-03-09 11:39:10
original
216 Les gens l'ont consulté

An Approach to Lazy Loading Custom Elements

Cet article explore une méthode de chargement paresseuse pour les éléments personnalisés afin d'améliorer les performances de la page Web. Cette méthode a été inspirée par les expériences des collègues, et son idée principale était de charger automatiquement le code d'implémentation correspondant après que des éléments personnalisés aient été ajoutés au DOM.

Habituellement, il n'y a pas besoin d'un mécanisme de chargement paresseux aussi complexe, mais les techniques décrites dans cet article sont encore précieuses pour des scénarios spécifiques.

Pour maintenir la cohérence, le chargeur paresseux lui-même est également conçu comme un élément personnalisé pour une configuration facile via HTML. Premièrement, nous devons identifier progressivement les éléments personnalisés non résolus:

class AutoLoader extends HTMLElement {
  connectedCallback() {
    const scope = this.parentNode;
    this.discover(scope);
  }
}
customElements.define("ce-autoloader", AutoLoader);
Copier après la connexion
Copier après la connexion

En supposant que nous avons préchargé ce module (idéalement en utilisant la méthode asynchrone), nous pouvons ajouter l'élément <ce-autoloader></ce-autoloader> au document. Cela commencera immédiatement le processus de recherche pour tous les éléments enfants qui forment l'élément racine. En ajoutant <ce-autoloader></ce-autoloader> à l'élément de conteneur correspondant, vous pouvez limiter la portée de la recherche au sous-arbre du document, et même utiliser plusieurs instances dans différents sous-arbres.

Ensuite, nous devons implémenter la méthode discover (dans le cadre de la classe ci-dessus): AutoLoader

discover(scope) {
  const candidates = [scope, ...scope.querySelectorAll("*")];
  for (const el of candidates) {
    const tag = el.localName;
    if (tag.includes("-") && !customElements.get(tag)) {
      this.load(tag);
    }
  }
}
Copier après la connexion
Ce code vérifie l'élément racine et tous ses descendants (*). Si l'élément est un élément personnalisé (une étiquette traitant d'union) mais n'a pas encore été mis à niveau, essayez de charger la définition correspondante. Cette méthode peut occuper une grande quantité de ressources de requête DOM, elle doit donc être gérée avec prudence. Nous pouvons réduire la charge sur le thread principal en retardant l'exécution:

connectedCallback() {
  const scope = this.parentNode;
  requestIdleCallback(() => {
    this.discover(scope);
  });
}
Copier après la connexion

Tous les navigateurs ne le prennent pas en charge, vous pouvez utiliser requestIdleCallback comme plan de sauvegarde: requestAnimationFrame

const defer = window.requestIdleCallback || requestAnimationFrame;

class AutoLoader extends HTMLElement {
  connectedCallback() {
    const scope = this.parentNode;
    defer(() => {
      this.discover(scope);
    });
  }
  // ...
}
Copier après la connexion
Maintenant, nous pouvons implémenter la méthode

, injecter dynamiquement les éléments load: <script></script>

load(tag) {
  const el = document.createElement("script");
  const res = new Promise((resolve, reject) => {
    el.addEventListener("load", () => resolve(null));
    el.addEventListener("error", () => reject(new Error("未能找到自定义元素定义")));
  });
  el.src = this.elementURL(tag);
  document.head.appendChild(el);
  return res;
}

elementURL(tag) {
  return `${this.rootDir}/${tag}.js`;
}
Copier après la connexion
Veuillez noter la convention codée dure dans

. L'URL de l'attribut elementURL suppose qu'il existe un répertoire contenant toutes les définitions des éléments personnalisés (par exemple src<my-widget></my-widget>). Nous pouvons adopter des stratégies plus complexes, mais cela suffit à nos fins. Déléguer cette URL à une méthode distincte pour permettre la sous-classe spécifique au projet si nécessaire: /components/my-widget.js

class FancyLoader extends AutoLoader {
  elementURL(tag) {
    // 自定义逻辑
  }
}
Copier après la connexion
De toute façon, nous comptons sur

. Il s'agit de la configurabilité mentionnée précédemment. Ajoutons un getter correspondant: this.rootDir

get rootDir() {
  const uri = this.getAttribute("root-dir");
  if (!uri) {
    throw new Error("无法自动加载自定义元素:缺少`root-dir`属性");
  }
  return uri.endsWith("/") ? uri.substring(0, uri.length - 1) : uri;
}
Copier après la connexion
Nous n'avons pas besoin d'utiliser

parce que la mise à jour de la propriété observedAttributes ne semble pas nécessaire au moment de l'exécution. root-dir

Maintenant, nous pouvons (et devons) configurer le répertoire des éléments:

. <ce-autoloader root-dir="/components"></ce-autoloader>

Avec cela, notre autoloader fonctionne. Mais cela ne fonctionne que pour des éléments qui existent déjà lorsque l'autofor est initialisé. Nous pouvons également avoir besoin de considérer des éléments ajoutés dynamiquement. C'est là que

entre en jeu: MutationObserver

class AutoLoader extends HTMLElement {
  connectedCallback() {
    const scope = this.parentNode;
    this.discover(scope);
  }
}
customElements.define("ce-autoloader", AutoLoader);
Copier après la connexion
Copier après la connexion

De cette manière, le navigateur nous informera lorsqu'un nouvel élément apparaît dans le DOM (plus précisément, notre sous-arbre correspondant), puis nous l'utilisons pour redémarrer le processus de recherche.

Notre Autoloader est désormais pleinement utilisable. Les améliorations futures peuvent inclure l'étude des conditions de compétition potentielles et l'optimisation. Mais pour la plupart des scénarios, cela suffit. Si vous avez une approche différente, faites-le moi savoir dans les commentaires et nous pouvons communiquer entre nous!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal