DocumentFragment: o que é e como (não) combatê-lo

Isenção de responsabilidade
Parece 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.

imagem

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); //   parentDiv.appendChild(fragment); console.log(parentDiv.children); 

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.

Source: https://habr.com/ru/post/pt413287/


All Articles