Qu'advient-il si nous manipuler le DOM dans requestAnimationFrame?

0

La question

Ma compréhension est lorsqu'il existe des raisons de manipulation du DOM, comme l'insertion d'un élément du DOM entraînerait une redistribution et, plus vraisemblablement, suivie par une mise à jour. S'il vous plaît corrigez-moi si je me trompe. Citant le MDN Web Docs,

De la fenêtre.requestAnimationFrame() méthode indique au navigateur que vous souhaitez effectuer une animation et demande que le navigateur appelle une fonction spécifiée pour mettre à jour une animation avant la prochaine repeindre

le requestAnimationFrame (un.k.un. aAF) de callback est appelée juste avant que le navigateur est sur le point de le repeindre. Donc, est-ce à dire si nous parviennent malgré tout à faire une manipulation du DOM à l'intérieur de ce rAF (edit: et aussi une autre file d'attente de la rAF à la fin) qui déclenche une redistribution à chaque fois et donc repeindre, on serait bloqué dans une boucle infinie sans vraiment rendu n'importe quoi sur l'écran.

Ou est-ce le cas qu'une fois que le navigateur a décidé de faire repeindre, il va rester avec elle et appliquer toutes les mises à jour qui s'est passé dans la royal air force de rappel dans le prochain repeindre?

dom javascript reflow repaint
2021-11-21 07:17:28
1

La meilleure réponse

1

chaque fois qu'il ya une certaine manipulation du DOM, comme l'insertion d'un élément du DOM entraînerait une redistribution et, plus vraisemblablement, suivie par une mise à jour

La peinture à l'action se produit de manière asynchrone, afin de "déclencher" doit être compris dans ce sens. D'abord votre code JavaScript sera fini avant que la réalité.

si nous parviennent malgré tout à faire une manipulation du DOM à l'intérieur de ce rAF (edit: et aussi une autre file d'attente de la rAF à la fin) qui déclenche une redistribution à chaque fois et donc repeindre, on serait bloqué dans une boucle infinie sans vraiment rendu n'importe quoi sur l'écran.

Les besoins pour repeindre s'accumulent et ne sont pas remplies de manière synchrone. D'abord votre code a remplir jusqu'à ce que la pile des appels est vide. Donc, il n'y a pas de boucle infinie ici.

Ou est-ce le cas qu'une fois que le navigateur a décidé de faire repeindre, il va rester avec elle et appliquer toutes les mises à jour qui s'est passé dans la royal air force de rappel dans le prochain repeindre?

Oui. Lorsque la RAF callback est appelée, que le code obtient une dernière chance de mettre à jour le DOM, ce qui peut s'accumuler davantage les besoins pour la peinture. Si, dans ce rappel vous avez également enregistrer un autre rappel sur la RAF, il n'exécutera pas à l'époque, mais plus tard: à la prochaine fois que le navigateur va préparer son repeindre tâche, afin de ne pas l'actuel.

Exemple simplifié

Disons que vous avez ce code:

requestAnimationFrame(update);

myElement.style.backgroundColor = "silver"; // This queues a need for repaint

function update() {
    // This queues a need for repaint
    myElement.style.width = Math.floor(Math.random() * 100) + "px";
    requestAnimationFrame(update);
}

Lorsque cela s'exécute, nous obtenons la séquence suivante:

  1. update est inscrit à titre de rappel
  2. Le changement d'arrière-plan des horaires un besoin de repeindre
  3. La pile des appels est vide
  4. Le navigateur démarre sa repeindre travail, mais prend en compte, il est un rappel enregistré. Afin de supprimer cet enregistrement (parce qu'il doit s'exécuter uniquement une fois) et s'exécute update avant de faire quoi que ce soit.
  5. La modification de la largeur des annexes a besoin de repeindre. La liste des changements inclut maintenant le changement d'arrière-plan et cette modification de la largeur et de tout effet de cascade qui a été calculé. (Comment cela est représenté, c'est le navigateur charge)
  6. L' update la fonction est inscrit à titre de rappel de nouveau.
  7. Le navigateur vérifie maintenant ce qu'il doit faire dans le cadre de cette repeindre travail, et effectue tout ce qui est nécessaire pour visualiser les effets de l'arrière-plan et la largeur des changements.
  8. Le travail de peinture se termine. Tout ce qui est à gauche est inscrit update de rappel.
  9. Lorsque le navigateur effectue son prochain cycle de peinture, on recommence à partir de l'étape 4, mais maintenant il n'y a pas de file d'attente d'arrière-plan de changement, pas plus. Pour le reste, il sera le même processus.
2021-11-21 12:57:10

"4. Le navigateur démarre sa mise en page/repeindre travail", c'est assez déroutant de la formulation, je pense que dire "le navigateur démarre la mise à jour du rendu" serait un peu moins à confusion. La mise en page et de le repeindre sont séparés, vous pouvez très bien la force d'une mise en page de façon synchrone du code de l'espace utilisateur, vous ne pouvez pas forcer une mise à jour, qui sera toujours la dernière étape de l'interprétation des mesures. Aussi, je sens les réponses à la première des points serait beaucoup plus simple, et en rappelant à partir de l'obtenir-aller qui raf(()=>raf(fn2)) calendrier des fn2 mettre le feu à la prochaine image. Sinon, cette réponse est correcte.
Kaiido

@Kaiido, merci pour votre commentaire. "vous pouvez très bien la force d'une mise en page de façon synchrone de l'utilisateur code de l'espace": voulez-vous dire à un utilisateur perceptible changement dans la présentation? pouvez-vous donner un exemple de code de qui?
trincot

De toute façon, j'ai supprimé la référence à la mise en page.
trincot

gist.github.com/paulirish/5d52fb081b3570c81e3a Voici une liste de ce qui déclenche la mise en page, et oui, c'est l'utilisateur "perceptible": stackoverflow.com/questions/55134528/...
Kaiido

Bon, Kaiido!
trincot

Dans d'autres langues

Cette page est dans d'autres langues

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................