Co se stane, když budeme manipulovat s DOM v requestAnimationFrame?

0

Otázka

Moje chápání je, že vždy, když je nějaký DOM manipulace, jako je vkládání DOM prvek by mohl vyvolat přeformátování a s největší pravděpodobností následuje překreslit. Prosím, opravte mě, pokud se mýlím. Cituji MDN Web Docs,

Na okno.requestAnimationFrame() metoda říká prohlížeči, že budete chtít provést animace a požaduje, aby prohlížeč zavolá zadanou funkci aktualizovat animaci před další repaint

na requestAnimationFrame (.k.a. aAF) callback je volána těsně předtím, než prohlížeč je o překreslit. Takže to znamená, pokud se nám nějak podaří udělat DOM manipulace uvnitř této rAF (edit: a také fronty další rAF na konci), který spouští reflow pokaždé, a tedy překreslit, bychom se zasekl v nekonečné smyčce, aniž by se skutečně činí něco na obrazovce.

Nebo je to tak, že jakmile prohlížeč se rozhodl udělat repaint, to bude držet se ho a aplikujte všechny aktualizace, které se stalo v RAF zpětné volání v příštím překreslit?

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

Nejlepší odpověď

1

vždy, když je nějaký DOM manipulace, jako je vkládání DOM prvek by mohl vyvolat přeformátování a s největší pravděpodobností následuje překreslit

Obraz akce dochází asynchronně, takže "trigger" by měla být chápána tímto způsobem. První váš JavaScript kód dokončit dříve, než se to opravdu stane.

pokud se nám nějak podaří udělat DOM manipulace uvnitř této rAF (edit: a také fronty další rAF na konci), který spouští reflow pokaždé, a tedy překreslit, bychom se zasekl v nekonečné smyčce, aniž by se skutečně činí něco na obrazovce.

Potřeby pro překreslit hromadí a nejsou současně splněny. První váš kód musí dokončit, dokud zásobník je prázdný. Takže tam je žádné nekonečné smyčky.

Nebo je to tak, že jakmile prohlížeč se rozhodl udělat repaint, to bude držet se ho a aplikujte všechny aktualizace, které se stalo v RAF zpětné volání v příštím překreslit?

Ano. Když RAF zpětného volání je volána, že se kód dostane poslední šanci, aby se aktualizace s DOM, které se mohou hromadit další potřeby pro malování. Pokud v tom, že zpětné volání můžete také zaregistrovat další zpětné volání na RAF, že nebude provádět v té době, ale později: v příští čas, který prohlížeč bude připravit svůj úkol překreslit ... takže není aktuální.

Zjednodušený příklad

Řekněme, že máte tento kód:

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);
}

Když to vykoná, dostaneme následující posloupnost:

  1. update je registrována jako callback
  2. Pozadí, změnit plány, potřeby pro malování
  3. Zásobník se vyprázdní
  4. Prohlížeč začne jeho překreslit práci, ale bere v úvahu, tam je registrovaná callback. Tak odstraňuje tuto registraci (protože to by mělo spustit pouze jednou) a spustí update předtím, než dělat něco jiného.
  5. Šířka změnit plány, potřeby pro malování. Seznam změn nyní obsahuje pozadí změnit a tato šířka změnu a kaskádový efekt, který se vypočte. (Jak je to zastoupení je závislý na prohlížeči)
  6. Na update funkce je registrována jako callback znovu.
  7. Prohlížeč nyní kontroluje, co je třeba udělat jako součást tohoto překreslit práci, a plní vše, co je potřeba vizualizovat efekty na pozadí a šířku změny.
  8. Lak končí. Vše, co je vlevo je registrovaná update zpětné volání.
  9. Když prohlížeč plní své další barvou cyklu, začneme znovu od kroku 4, ale nyní není ve frontě na pozadí-změna. Pro ostatní to bude stejný proces.
2021-11-21 12:57:10

"4. Prohlížeč začne jeho uspořádání/překreslit práci," to je docela matoucí formulace, myslím, že rčení "prohlížeč spustí aktualizace rendering" by být trochu méně matoucí. Rozložení a překreslit jsou odděleny, můžete velmi dobře vynutit rozložení synchronně od uživatele-kód země, nemůžeš vynutit překreslení, což je vždy poslední krok vykreslování kroky. Také, mám pocit, že odpovědi na první body by bylo mnohem jednodušší, tím, že připomene z get-go, že raf(()=>raf(fn2)) bude rozvrh fn2 k požáru na další snímek. Jinak tato odpověď je správná.
Kaiido

@Kaiido, díky za váš komentář. "můžete velmi dobře vynutit rozložení synchronně od uživatele-kód země": tím myslíš uživatelsky vnímatelné změny v rozvržení? můžete dát příklad kódu?
trincot

Jakýmkoli způsobem, že jsem odstranil odkaz na layout.
trincot

gist.github.com/paulirish/5d52fb081b3570c81e3a Zde je seznam, co spouští rozložení, a ano, je to "uživatelsky vnímatelné": stackoverflow.com/questions/55134528/...
Kaiido

Dobře, Kaiido!
trincot

V jiných jazycích

Tato stránka je v jiných jazycích

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