Isenção de responsabilidadeParece que estou começando uma nova série de artigos - um pouco chata e puramente utilitária. Eles vão explicar os pontos que muitas vezes causam dificuldades aos meus alunos. Se você é um desenvolvedor web experiente, provavelmente não estará interessado. Se você está esperando por perversões no poder do JS de sexta-feira, elas não estarão aqui, infelizmente.
Uma das coisas que os alunos costumam ter problemas para entender é o DocumentFragment. Em geral, não posso culpá-los. Com simplicidade externa, possui várias propriedades não óbvias e até contra-intuitivas. Neste artigo, quero coletar tudo o que um iniciante precisa saber sobre ele.

O que é isso
Um DocumentFragment é um contêiner que pode conter um número arbitrário de elementos DOM. Se bem simples, você pode imaginá-lo como um balde. Os elementos são empilhados para que, no momento certo, possam ser descartados imediatamente.
Como criar
Elementar.
var fragment = document.createDocumentFragment();
Existem também outras maneiras, mas sobre elas abaixo.
Por que eu preciso
Como escrevi acima, para armazenar elementos DOM. "Mas eles podem ser armazenados em uma diva comum", o leitor pode objetar. É verdade que o fragmento possui uma propriedade exclusiva que o torna o melhor candidato para esse papel. Considere o seguinte código:
var fragment = document.createDocumentFragment(); var parentDiv = document.createElement("div"); var div1 = document.createElement("div"); var div2 = document.createElement("div"); fragment.appendChild(div1); fragment.appendChild(div2);
O que o console nos dirá? Uma pessoa não familiarizada com DocumentFragment pode pensar que
parentDiv
terá um
fragment
filho. Mas, de fato, ele terá dois filhos -
div1
e
div2
. O fato é que o fragmento em si não é um elemento DOM, é apenas um contêiner para elementos DOM. E quando é passado como argumento para métodos como
appendChild
ou
insertBefore
, ele não incorpora na árvore DOM, mas incorpora seu conteúdo lá.
Mas por que você precisa disso?
A propriedade "bucket" é, obviamente, boa, mas como isso é útil na prática? O DocumentFragment possui duas áreas principais de aplicação.
1. Armazenando pedaços de HTML que não têm um ancestral comum.Há situações em que precisamos substituir o conteúdo de um elemento, mas não tocamos no próprio elemento. Suponha que usemos delegação de eventos, e todos os manipuladores de eventos que ocorrem em elementos internos estão pendurados em uma div externa. Nesse caso, o DocumentFragment é ideal para nós:
div.innerHTML = ""; div.appendChild(fragmentWithAllContent);
"Mas podemos adicionar elementos à div imediatamente quando os criamos?" - o leitor corrosivo perguntará. Podemos, mas não vale a pena, e é por isso.
2. Melhoria de desempenho no caso de várias inserções.O fato é que toda vez que alteramos algo na árvore DOM ativa, o navegador precisa fazer vários cálculos. Você pode ler mais sobre isso
aqui , por exemplo. Neste artigo, restringimos-nos a mencionar que existe um animal tão terrível - reflow. Quando adicionamos um elemento à página, essa fera acorda e consome um tempo do processador. Se adicionarmos cem elementos por vez, o animal acordará cem vezes e fará uma mordida cem vezes. Para o usuário, isso já pode ser notável "congelar".
Quando adicionamos um elemento ao DocumentFragment, isso não causa reflow, porque o fragmento não faz (e basicamente não pode ser) parte da árvore DOM ativa. E o mais importante: quando inserimos o conteúdo de um fragmento usando
appendChild
ou outros métodos semelhantes, independentemente de quantos elementos estejam dentro do fragmento, o
reflow é chamado apenas uma vez .
Para maior clareza, fiz uma
referência simples para que o leitor possa ver pessoalmente a diferença.
Upd: o camarada
nuit disse que, para o Chrome moderno, minhas palavras não são mais verdadeiras. Nele, o reflow não é executado antes do necessário e, graças a isso, o código sem o DocumentFragment realmente funciona
mais rápido e, com outros navegadores, não é tão óbvio. Portanto, antes de decidir usar fragmentos, é necessário criar um perfil e pesquisar o público-alvo do site.
Nuances
Existem dois recursos que dificultam o uso de fragmentos para iniciantes. Primeiro: como escrevi acima, um fragmento
não é
um elemento DOM . Isso significa que faltam muitos métodos e propriedades familiares, em particular -
innerHTML
. Portanto, você não pode simplesmente transformar uma string no conteúdo de um fragmento. Como fazer isso não é fácil, será descrito abaixo.
A segunda característica: o fragmento ao usar "despojos". Mais precisamente, é esvaziado. Quando fazemos
div.appendChild(fragment)
, todos os filhos do fragmento são
div.appendChild(fragment)
em uma
div
. E como um elemento não pode ter mais de um pai, isso significa que eles são removidos do fragmento! Para evitar esse comportamento quando for indesejável, você pode usar o
cloneNode
.
tag <template>
Há um lugar onde você pode encontrar o DocumentFragment sem criá-lo através do JS. Esta é a propriedade
content
do elemento template.
A
<template>
inventada especificamente para armazenar partes do código HTML, mas não para carregar o navegador antes do tempo. O conteúdo desta tag não se torna parte da árvore DOM ativa. Em particular (os recém-chegados também costumam se deparar com isso), eles não podem ser encontrados usando o
querySelector
. Os elementos criados a partir do código HTML dentro da tag
<template>
não se tornam filhos dela. Em vez disso, o JavaScript pode acessá-los através da propriedade
content
, o que é uma surpresa! - apenas DocumentFragment.
Usando o elemento de modelo, você pode criar um fragmento a partir de uma sequência:
function createFragmentFromString(str){ var template = document.createElement("template"); template.innerHTML = str; return template.content; }
Epílogo
Se você é novo no desenvolvimento web, espero que tenha aprendido muito. Se você é um desenvolvedor experiente, pode complementar este artigo com algo. Nesse caso, não hesite em escrever sobre isso nos comentários. Obrigado pela leitura e tenha um bom dia.