Insertar en el DOM dentro de un bucle
Meter 500 nodos uno a uno provoca 500 recálculos. Cómo bajar a uno.
- reflow
- batching
- DocumentFragment
El problema
Necesitas pintar una lista de 500 elementos. Escribes lo obvio: un bucle
con createElement y appendChild. Funciona, pero se nota lento en móvil.
El motivo no es el bucle. Es que cada appendChild es una modificación al
árbol del DOM, y el navegador tiene que estar preparado en cualquier
momento para responder a preguntas sobre layout (offsetHeight,
getBoundingClientRect). Aunque en la práctica intenta agrupar reflows,
un patrón de 500 mutaciones seguidas es exactamente lo que le impide hacerlo.
El código “roto”
const container = document.getElementById("list");
for (let i = 0; i < 500; i++) {
const item = document.createElement("div");
item.textContent = "Elemento " + i;
container.appendChild(item);
}
Las pistas
- Los nodos no tienen por qué vivir en el DOM mientras los construyes.
- Buscas una única operación al final del bucle, no 500.
DocumentFragmentexiste exactamente para esto.
Ver la solución
const container = document.getElementById("list");
const fragment = document.createDocumentFragment();
for (let i = 0; i < 500; i++) {
const item = document.createElement("div");
item.textContent = "Elemento " + i;
fragment.appendChild(item);
}
container.appendChild(fragment);Un DocumentFragment es un contenedor ligero que no forma parte del
documento visible. Puedes montar dentro toda la lista sin que el navegador
reflowee nada, y cuando insertas el fragmento en el contenedor real, el
DOM ve una sola inserción, no 500.
También sirve un array + spread, que expresa la misma idea de otra manera:
const container = document.getElementById("list");
const items = [];
for (let i = 0; i < 500; i++) {
const item = document.createElement("div");
item.textContent = "Elemento " + i;
items.push(item);
}
container.append(...items);El DocumentFragment es el patrón canónico de la plataforma; el array +
spread lee bien y no necesita conocerlo. Cualquiera vale, siempre que se
pase de N mutaciones a una.
500 tarjetas, con y sin fragment
Pulsa los dos botones y compara. Ambos meten 500 elementos en el DOM; la diferencia está en cuántas veces el navegador tiene que replantear layout: 500 con la versión rota (una modificación por iteración), una sola conDocumentFragment. Abre la pestaña Performancede las devtools para verlo en el timeline.
Comprueba lo que has aprendido
1. ¿Por qué es lento insertar 500 nodos con appendChild dentro de un bucle?
2. ¿Qué hace un DocumentFragment y por qué ayuda aquí?
3. Al hacer `container.append(...items)` con 500 elementos, ¿cuántos reflows fuerza?
4. ¿Cuál de estas variantes también sirve para bajar los 500 reflows a uno?
5. ¿Qué es exactamente un “reflow”?